Merge pull request #9726 from Icinga/43624b

Remove -and notify- expired downtimes immediately, not every 60s II
This commit is contained in:
Julian Brost 2023-05-02 11:25:03 +02:00 committed by GitHub
commit af9d67b262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 178 additions and 75 deletions

View File

@ -232,7 +232,7 @@ static void TypeInfoTimerHandler()
} }
INITIALIZE_ONCE([]() { INITIALIZE_ONCE([]() {
l_ObjectCountTimer = new Timer(); l_ObjectCountTimer = Timer::Create();
l_ObjectCountTimer->SetInterval(10); l_ObjectCountTimer->SetInterval(10);
l_ObjectCountTimer->OnTimerExpired.connect([](const Timer * const&) { TypeInfoTimerHandler(); }); l_ObjectCountTimer->OnTimerExpired.connect([](const Timer * const&) { TypeInfoTimerHandler(); });
l_ObjectCountTimer->Start(); l_ObjectCountTimer->Start();

View File

@ -28,7 +28,7 @@ void StreamLogger::Stop(bool runtimeRemoved)
StreamLogger::~StreamLogger() StreamLogger::~StreamLogger()
{ {
if (m_FlushLogTimer) if (m_FlushLogTimer)
m_FlushLogTimer->Stop(); m_FlushLogTimer->Stop(true);
if (m_Stream && m_OwnsStream) if (m_Stream && m_OwnsStream)
delete m_Stream; delete m_Stream;
@ -58,7 +58,7 @@ void StreamLogger::BindStream(std::ostream *stream, bool ownsStream)
m_OwnsStream = ownsStream; m_OwnsStream = ownsStream;
if (!m_FlushLogTimer) { if (!m_FlushLogTimer) {
m_FlushLogTimer = new Timer(); m_FlushLogTimer = Timer::Create();
m_FlushLogTimer->SetInterval(1); m_FlushLogTimer->SetInterval(1);
m_FlushLogTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushLogTimerHandler(); }); m_FlushLogTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushLogTimerHandler(); });
m_FlushLogTimer->Start(); m_FlushLogTimer->Start();

View File

@ -12,6 +12,7 @@
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <utility>
using namespace icinga; using namespace icinga;
@ -61,6 +62,15 @@ static int l_AliveTimers = 0;
static Defer l_ShutdownTimersCleanlyOnExit (&Timer::Uninitialize); static Defer l_ShutdownTimersCleanlyOnExit (&Timer::Uninitialize);
Timer::Ptr Timer::Create()
{
Ptr t (new Timer());
t->m_Self = t;
return t;
}
/** /**
* Destructor for the Timer class. * Destructor for the Timer class.
*/ */
@ -151,16 +161,15 @@ double Timer::GetInterval() const
*/ */
void Timer::Start() void Timer::Start()
{ {
{ std::unique_lock<std::mutex> lock(l_TimerMutex);
std::unique_lock<std::mutex> lock(l_TimerMutex);
m_Started = true;
if (++l_AliveTimers == 1) { if (!m_Started && ++l_AliveTimers == 1) {
InitializeThread(); InitializeThread();
}
} }
InternalReschedule(false); m_Started = true;
InternalRescheduleUnlocked(false, m_Interval > 0 ? -1 : m_Next);
} }
/** /**
@ -192,6 +201,13 @@ void Timer::Reschedule(double next)
InternalReschedule(false, next); InternalReschedule(false, next);
} }
void Timer::InternalReschedule(bool completed, double next)
{
std::unique_lock<std::mutex> lock (l_TimerMutex);
InternalRescheduleUnlocked(completed, next);
}
/** /**
* Reschedules this timer. * Reschedules this timer.
* *
@ -199,10 +215,8 @@ void Timer::Reschedule(double next)
* @param next The time when this timer should be called again. Use -1 to let * @param next The time when this timer should be called again. Use -1 to let
* the timer figure out a suitable time based on the interval. * the timer figure out a suitable time based on the interval.
*/ */
void Timer::InternalReschedule(bool completed, double next) void Timer::InternalRescheduleUnlocked(bool completed, double next)
{ {
std::unique_lock<std::mutex> lock(l_TimerMutex);
if (completed) if (completed)
m_Running = false; m_Running = false;
@ -238,7 +252,7 @@ double Timer::GetNext() const
} }
/** /**
* Adjusts all timers by adding the specified amount of time to their * Adjusts all periodic timers by adding the specified amount of time to their
* next scheduled timestamp. * next scheduled timestamp.
* *
* @param adjustment The adjustment. * @param adjustment The adjustment.
@ -255,6 +269,11 @@ void Timer::AdjustTimers(double adjustment)
std::vector<Timer *> timers; std::vector<Timer *> timers;
for (Timer *timer : idx) { for (Timer *timer : idx) {
/* Don't schedule the next call if this is not a periodic timer. */
if (timer->m_Interval <= 0) {
continue;
}
if (std::fabs(now - (timer->m_Next + adjustment)) < if (std::fabs(now - (timer->m_Next + adjustment)) <
std::fabs(now - timer->m_Next)) { std::fabs(now - timer->m_Next)) {
timer->m_Next += adjustment; timer->m_Next += adjustment;
@ -282,9 +301,9 @@ void Timer::TimerThreadProc()
Utility::SetThreadName("Timer Thread"); Utility::SetThreadName("Timer Thread");
for (;;) { std::unique_lock<std::mutex> lock (l_TimerMutex);
std::unique_lock<std::mutex> lock(l_TimerMutex);
for (;;) {
typedef boost::multi_index::nth_index<TimerSet, 1>::type NextTimerView; typedef boost::multi_index::nth_index<TimerSet, 1>::type NextTimerView;
NextTimerView& idx = boost::get<1>(l_Timers); NextTimerView& idx = boost::get<1>(l_Timers);
@ -316,11 +335,20 @@ void Timer::TimerThreadProc()
* until the current call is completed. */ * until the current call is completed. */
l_Timers.erase(timer); l_Timers.erase(timer);
auto keepAlive (timer->m_Self.lock());
if (!keepAlive) {
// The last std::shared_ptr is gone, let ~Timer() proceed
continue;
}
timer->m_Running = true; timer->m_Running = true;
lock.unlock(); lock.unlock();
/* Asynchronously call the timer. */ /* Asynchronously call the timer. */
Utility::QueueAsyncCallback([timer]() { timer->Call(); }); Utility::QueueAsyncCallback([timer=std::move(keepAlive)]() { timer->Call(); });
lock.lock();
} }
} }

View File

@ -4,8 +4,8 @@
#define TIMER_H #define TIMER_H
#include "base/i2-base.hpp" #include "base/i2-base.hpp"
#include "base/object.hpp"
#include <boost/signals2.hpp> #include <boost/signals2.hpp>
#include <memory>
namespace icinga { namespace icinga {
@ -16,12 +16,14 @@ class TimerHolder;
* *
* @ingroup base * @ingroup base
*/ */
class Timer final : public Object class Timer final
{ {
public: public:
DECLARE_PTR_TYPEDEFS(Timer); typedef std::shared_ptr<Timer> Ptr;
~Timer() override; static Ptr Create();
~Timer();
static void Initialize(); static void Initialize();
static void Uninitialize(); static void Uninitialize();
@ -46,9 +48,12 @@ private:
double m_Next{0}; /**< When the next event should happen. */ double m_Next{0}; /**< When the next event should happen. */
bool m_Started{false}; /**< Whether the timer is enabled. */ bool m_Started{false}; /**< Whether the timer is enabled. */
bool m_Running{false}; /**< Whether the timer proc is currently running. */ bool m_Running{false}; /**< Whether the timer proc is currently running. */
std::weak_ptr<Timer> m_Self;
Timer() = default;
void Call(); void Call();
void InternalReschedule(bool completed, double next = -1); void InternalReschedule(bool completed, double next = -1);
void InternalRescheduleUnlocked(bool completed, double next = -1);
static void TimerThreadProc(); static void TimerThreadProc();

View File

@ -21,7 +21,7 @@ WorkQueue::WorkQueue(size_t maxItems, int threadCount, LogSeverity statsLogLevel
/* Initialize logger. */ /* Initialize logger. */
m_StatusTimerTimeout = Utility::GetTime(); m_StatusTimerTimeout = Utility::GetTime();
m_StatusTimer = new Timer(); m_StatusTimer = Timer::Create();
m_StatusTimer->SetInterval(10); m_StatusTimer->SetInterval(10);
m_StatusTimer->OnTimerExpired.connect([this](const Timer * const&) { StatusTimerHandler(); }); m_StatusTimer->OnTimerExpired.connect([this](const Timer * const&) { StatusTimerHandler(); });
m_StatusTimer->Start(); m_StatusTimer->Start();

View File

@ -67,7 +67,7 @@ void CheckerComponent::Start(bool runtimeCreated)
m_Thread = std::thread([this]() { CheckThreadProc(); }); m_Thread = std::thread([this]() { CheckThreadProc(); });
m_ResultTimer = new Timer(); m_ResultTimer = Timer::Create();
m_ResultTimer->SetInterval(5); m_ResultTimer->SetInterval(5);
m_ResultTimer->OnTimerExpired.connect([this](const Timer * const&) { ResultTimerHandler(); }); m_ResultTimer->OnTimerExpired.connect([this](const Timer * const&) { ResultTimerHandler(); });
m_ResultTimer->Start(); m_ResultTimer->Start();
@ -81,7 +81,7 @@ void CheckerComponent::Stop(bool runtimeRemoved)
m_CV.notify_all(); m_CV.notify_all();
} }
m_ResultTimer->Stop(); m_ResultTimer->Stop(true);
m_Thread.join(); m_Thread.join();
Log(LogInformation, "CheckerComponent") Log(LogInformation, "CheckerComponent")

View File

@ -69,7 +69,7 @@ void CompatLogger::Start(bool runtimeCreated)
ExternalCommandHandler(command, arguments); ExternalCommandHandler(command, arguments);
}); });
m_RotationTimer = new Timer(); m_RotationTimer = Timer::Create();
m_RotationTimer->OnTimerExpired.connect([this](const Timer * const&) { RotationTimerHandler(); }); m_RotationTimer->OnTimerExpired.connect([this](const Timer * const&) { RotationTimerHandler(); });
m_RotationTimer->Start(); m_RotationTimer->Start();
@ -82,6 +82,8 @@ void CompatLogger::Start(bool runtimeCreated)
*/ */
void CompatLogger::Stop(bool runtimeRemoved) void CompatLogger::Stop(bool runtimeRemoved)
{ {
m_RotationTimer->Stop(true);
Log(LogInformation, "CompatLogger") Log(LogInformation, "CompatLogger")
<< "'" << GetName() << "' stopped."; << "'" << GetName() << "' stopped.";

View File

@ -83,14 +83,14 @@ void DbConnection::Resume()
Log(LogInformation, "DbConnection") Log(LogInformation, "DbConnection")
<< "Resuming IDO connection: " << GetName(); << "Resuming IDO connection: " << GetName();
m_CleanUpTimer = new Timer(); m_CleanUpTimer = Timer::Create();
m_CleanUpTimer->SetInterval(60); m_CleanUpTimer->SetInterval(60);
m_CleanUpTimer->OnTimerExpired.connect([this](const Timer * const&) { CleanUpHandler(); }); m_CleanUpTimer->OnTimerExpired.connect([this](const Timer * const&) { CleanUpHandler(); });
m_CleanUpTimer->Start(); m_CleanUpTimer->Start();
m_LogStatsTimeout = 0; m_LogStatsTimeout = 0;
m_LogStatsTimer = new Timer(); m_LogStatsTimer = Timer::Create();
m_LogStatsTimer->SetInterval(10); m_LogStatsTimer->SetInterval(10);
m_LogStatsTimer->OnTimerExpired.connect([this](const Timer * const&) { LogStatsHandler(); }); m_LogStatsTimer->OnTimerExpired.connect([this](const Timer * const&) { LogStatsHandler(); });
m_LogStatsTimer->Start(); m_LogStatsTimer->Start();
@ -101,7 +101,8 @@ void DbConnection::Pause()
Log(LogInformation, "DbConnection") Log(LogInformation, "DbConnection")
<< "Pausing IDO connection: " << GetName(); << "Pausing IDO connection: " << GetName();
m_CleanUpTimer.reset(); m_LogStatsTimer->Stop(true);
m_CleanUpTimer->Stop(true);
DbQuery query1; DbQuery query1;
query1.Table = "programstatus"; query1.Table = "programstatus";
@ -135,7 +136,7 @@ void DbConnection::Pause()
void DbConnection::InitializeDbTimer() void DbConnection::InitializeDbTimer()
{ {
m_ProgramStatusTimer = new Timer(); m_ProgramStatusTimer = Timer::Create();
m_ProgramStatusTimer->SetInterval(10); m_ProgramStatusTimer->SetInterval(10);
m_ProgramStatusTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateProgramStatus(); }); m_ProgramStatusTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateProgramStatus(); });
m_ProgramStatusTimer->Start(); m_ProgramStatusTimer->Start();

View File

@ -85,12 +85,12 @@ void IdoMysqlConnection::Resume()
/* Immediately try to connect on Resume() without timer. */ /* Immediately try to connect on Resume() without timer. */
m_QueryQueue.Enqueue([this]() { Reconnect(); }, PriorityImmediate); m_QueryQueue.Enqueue([this]() { Reconnect(); }, PriorityImmediate);
m_TxTimer = new Timer(); m_TxTimer = Timer::Create();
m_TxTimer->SetInterval(1); m_TxTimer->SetInterval(1);
m_TxTimer->OnTimerExpired.connect([this](const Timer * const&) { NewTransaction(); }); m_TxTimer->OnTimerExpired.connect([this](const Timer * const&) { NewTransaction(); });
m_TxTimer->Start(); m_TxTimer->Start();
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&){ ReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&){ ReconnectTimerHandler(); });
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -108,7 +108,8 @@ void IdoMysqlConnection::Pause()
DbConnection::Pause(); DbConnection::Pause();
m_ReconnectTimer.reset(); m_ReconnectTimer->Stop(true);
m_TxTimer->Stop(true);
#ifdef I2_DEBUG /* I2_DEBUG */ #ifdef I2_DEBUG /* I2_DEBUG */
Log(LogDebug, "IdoMysqlConnection") Log(LogDebug, "IdoMysqlConnection")

View File

@ -92,12 +92,12 @@ void IdoPgsqlConnection::Resume()
/* Immediately try to connect on Resume() without timer. */ /* Immediately try to connect on Resume() without timer. */
m_QueryQueue.Enqueue([this]() { Reconnect(); }, PriorityImmediate); m_QueryQueue.Enqueue([this]() { Reconnect(); }, PriorityImmediate);
m_TxTimer = new Timer(); m_TxTimer = Timer::Create();
m_TxTimer->SetInterval(1); m_TxTimer->SetInterval(1);
m_TxTimer->OnTimerExpired.connect([this](const Timer * const&) { NewTransaction(); }); m_TxTimer->OnTimerExpired.connect([this](const Timer * const&) { NewTransaction(); });
m_TxTimer->Start(); m_TxTimer->Start();
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); });
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -112,7 +112,8 @@ void IdoPgsqlConnection::Pause()
{ {
DbConnection::Pause(); DbConnection::Pause();
m_ReconnectTimer.reset(); m_ReconnectTimer->Stop(true);
m_TxTimer->Stop(true);
Log(LogInformation, "IdoPgsqlConnection") Log(LogInformation, "IdoPgsqlConnection")
<< "'" << GetName() << "' paused."; << "'" << GetName() << "' paused.";

View File

@ -101,12 +101,12 @@ void Checkable::Start(bool runtimeCreated)
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, []() { boost::call_once(once, []() {
l_CheckablesFireSuppressedNotifications = new Timer(); l_CheckablesFireSuppressedNotifications = Timer::Create();
l_CheckablesFireSuppressedNotifications->SetInterval(5); l_CheckablesFireSuppressedNotifications->SetInterval(5);
l_CheckablesFireSuppressedNotifications->OnTimerExpired.connect(&Checkable::FireSuppressedNotificationsTimer); l_CheckablesFireSuppressedNotifications->OnTimerExpired.connect(&Checkable::FireSuppressedNotificationsTimer);
l_CheckablesFireSuppressedNotifications->Start(); l_CheckablesFireSuppressedNotifications->Start();
l_CleanDeadlinedExecutions = new Timer(); l_CleanDeadlinedExecutions = Timer::Create();
l_CleanDeadlinedExecutions->SetInterval(300); l_CleanDeadlinedExecutions->SetInterval(300);
l_CleanDeadlinedExecutions->OnTimerExpired.connect(&Checkable::CleanDeadlinedExecutions); l_CleanDeadlinedExecutions->OnTimerExpired.connect(&Checkable::CleanDeadlinedExecutions);
l_CleanDeadlinedExecutions->Start(); l_CleanDeadlinedExecutions->Start();

View File

@ -54,7 +54,7 @@ void ClusterEvents::EnqueueCheck(const MessageOrigin::Ptr& origin, const Diction
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, []() { boost::call_once(once, []() {
m_LogTimer = new Timer(); m_LogTimer = Timer::Create();
m_LogTimer->SetInterval(10); m_LogTimer->SetInterval(10);
m_LogTimer->OnTimerExpired.connect([](const Timer * const&) { LogRemoteCheckQueueInformation(); }); m_LogTimer->OnTimerExpired.connect([](const Timer * const&) { LogRemoteCheckQueueInformation(); });
m_LogTimer->Start(); m_LogTimer->Start();

View File

@ -81,7 +81,7 @@ void Comment::Start(bool runtimeCreated)
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, [this]() { boost::call_once(once, [this]() {
l_CommentsExpireTimer = new Timer(); l_CommentsExpireTimer = Timer::Create();
l_CommentsExpireTimer->SetInterval(60); l_CommentsExpireTimer->SetInterval(60);
l_CommentsExpireTimer->OnTimerExpired.connect([](const Timer * const&) { CommentsExpireTimerHandler(); }); l_CommentsExpireTimer->OnTimerExpired.connect([](const Timer * const&) { CommentsExpireTimerHandler(); });
l_CommentsExpireTimer->Start(); l_CommentsExpireTimer->Start();

View File

@ -10,13 +10,14 @@
#include "base/timer.hpp" #include "base/timer.hpp"
#include <boost/thread/once.hpp> #include <boost/thread/once.hpp>
#include <cmath> #include <cmath>
#include <utility>
using namespace icinga; using namespace icinga;
static int l_NextDowntimeID = 1; static int l_NextDowntimeID = 1;
static std::mutex l_DowntimeMutex; static std::mutex l_DowntimeMutex;
static std::map<int, String> l_LegacyDowntimesCache; static std::map<int, String> l_LegacyDowntimesCache;
static Timer::Ptr l_DowntimesExpireTimer; static Timer::Ptr l_DowntimesOrphanedTimer;
static Timer::Ptr l_DowntimesStartTimer; static Timer::Ptr l_DowntimesStartTimer;
boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeAdded; boost::signals2::signal<void (const Downtime::Ptr&)> Downtime::OnDowntimeAdded;
@ -93,15 +94,15 @@ void Downtime::Start(bool runtimeCreated)
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, [this]() { boost::call_once(once, [this]() {
l_DowntimesStartTimer = new Timer(); l_DowntimesStartTimer = Timer::Create();
l_DowntimesStartTimer->SetInterval(5); l_DowntimesStartTimer->SetInterval(5);
l_DowntimesStartTimer->OnTimerExpired.connect([](const Timer * const&){ DowntimesStartTimerHandler(); }); l_DowntimesStartTimer->OnTimerExpired.connect([](const Timer * const&){ DowntimesStartTimerHandler(); });
l_DowntimesStartTimer->Start(); l_DowntimesStartTimer->Start();
l_DowntimesExpireTimer = new Timer(); l_DowntimesOrphanedTimer = Timer::Create();
l_DowntimesExpireTimer->SetInterval(60); l_DowntimesOrphanedTimer->SetInterval(60);
l_DowntimesExpireTimer->OnTimerExpired.connect([](const Timer * const&) { DowntimesExpireTimerHandler(); }); l_DowntimesOrphanedTimer->OnTimerExpired.connect([](const Timer * const&) { DowntimesOrphanedTimerHandler(); });
l_DowntimesExpireTimer->Start(); l_DowntimesOrphanedTimer->Start();
}); });
{ {
@ -132,7 +133,8 @@ void Downtime::Start(bool runtimeCreated)
Log(LogNotice, "Downtime") Log(LogNotice, "Downtime")
<< "Checkable '" << checkable->GetName() << "' already in a NOT-OK state." << "Checkable '" << checkable->GetName() << "' already in a NOT-OK state."
<< " Triggering downtime now."; << " Triggering downtime now.";
TriggerDowntime(checkable->GetLastStateChange());
TriggerDowntime(std::fmax(std::fmax(GetStartTime(), GetEntryTime()), checkable->GetLastStateChange()));
} }
if (GetFixed() && CanBeTriggered()) { if (GetFixed() && CanBeTriggered()) {
@ -159,6 +161,21 @@ void Downtime::Stop(bool runtimeRemoved)
ObjectImpl<Downtime>::Stop(runtimeRemoved); ObjectImpl<Downtime>::Stop(runtimeRemoved);
} }
void Downtime::Pause()
{
if (m_CleanupTimer) {
m_CleanupTimer->Stop();
}
ObjectImpl<Downtime>::Pause();
}
void Downtime::Resume()
{
ObjectImpl<Downtime>::Resume();
SetupCleanupTimer();
}
Checkable::Ptr Downtime::GetCheckable() const Checkable::Ptr Downtime::GetCheckable() const
{ {
return static_pointer_cast<Checkable>(m_Checkable); return static_pointer_cast<Checkable>(m_Checkable);
@ -427,6 +444,28 @@ bool Downtime::CanBeTriggered()
return true; return true;
} }
void Downtime::SetupCleanupTimer()
{
if (!m_CleanupTimer) {
m_CleanupTimer = Timer::Create();
auto name (GetName());
m_CleanupTimer->OnTimerExpired.connect([name=std::move(name)](const Timer * const&) {
auto downtime (Downtime::GetByName(name));
if (downtime && downtime->IsExpired()) {
RemoveDowntime(name, false, false, true);
}
});
}
auto triggerTime (GetTriggerTime());
m_CleanupTimer->Reschedule((GetFixed() || triggerTime <= 0 ? GetEndTime() : triggerTime + GetDuration()) + 0.1);
m_CleanupTimer->Start();
}
void Downtime::TriggerDowntime(double triggerTime) void Downtime::TriggerDowntime(double triggerTime)
{ {
if (!CanBeTriggered()) if (!CanBeTriggered())
@ -441,6 +480,11 @@ void Downtime::TriggerDowntime(double triggerTime)
SetTriggerTime(triggerTime); SetTriggerTime(triggerTime);
} }
{
ObjectLock olock (this);
SetupCleanupTimer();
}
Array::Ptr triggers = GetTriggers(); Array::Ptr triggers = GetTriggers();
{ {
@ -497,11 +541,11 @@ void Downtime::DowntimesStartTimerHandler()
} }
} }
void Downtime::DowntimesExpireTimerHandler() void Downtime::DowntimesOrphanedTimerHandler()
{ {
for (const Downtime::Ptr& downtime : ConfigType::GetObjectsByType<Downtime>()) { for (const Downtime::Ptr& downtime : ConfigType::GetObjectsByType<Downtime>()) {
/* Only remove downtimes which are activated after daemon start. */ /* Only remove downtimes which are activated after daemon start. */
if (downtime->IsActive() && (downtime->IsExpired() || !downtime->HasValidConfigOwner())) if (downtime->IsActive() && !downtime->HasValidConfigOwner())
RemoveDowntime(downtime->GetName(), false, false, true); RemoveDowntime(downtime->GetName(), false, false, true);
} }
} }

View File

@ -72,6 +72,9 @@ protected:
void Start(bool runtimeCreated) override; void Start(bool runtimeCreated) override;
void Stop(bool runtimeRemoved) override; void Stop(bool runtimeRemoved) override;
void Pause() override;
void Resume() override;
void ValidateStartTime(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils) override; void ValidateStartTime(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils) override;
void ValidateEndTime(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils) override; void ValidateEndTime(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils) override;
@ -81,10 +84,14 @@ private:
std::set<Downtime::Ptr> m_Children; std::set<Downtime::Ptr> m_Children;
mutable std::mutex m_ChildrenMutex; mutable std::mutex m_ChildrenMutex;
Timer::Ptr m_CleanupTimer;
bool CanBeTriggered(); bool CanBeTriggered();
void SetupCleanupTimer();
static void DowntimesStartTimerHandler(); static void DowntimesStartTimerHandler();
static void DowntimesExpireTimerHandler(); static void DowntimesOrphanedTimerHandler();
}; };
} }

View File

@ -104,7 +104,7 @@ int IcingaApplication::Main()
Log(LogDebug, "IcingaApplication", "In IcingaApplication::Main()"); Log(LogDebug, "IcingaApplication", "In IcingaApplication::Main()");
/* periodically dump the program state */ /* periodically dump the program state */
l_RetentionTimer = new Timer(); l_RetentionTimer = Timer::Create();
l_RetentionTimer->SetInterval(300); l_RetentionTimer->SetInterval(300);
l_RetentionTimer->OnTimerExpired.connect([this](const Timer * const&) { DumpProgramState(); }); l_RetentionTimer->OnTimerExpired.connect([this](const Timer * const&) { DumpProgramState(); });
l_RetentionTimer->Start(); l_RetentionTimer->Start();

View File

@ -78,7 +78,7 @@ void ScheduledDowntime::Start(bool runtimeCreated)
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, [this]() { boost::call_once(once, [this]() {
l_Timer = new Timer(); l_Timer = Timer::Create();
l_Timer->SetInterval(60); l_Timer->SetInterval(60);
l_Timer->OnTimerExpired.connect([](const Timer * const&) { TimerProc(); }); l_Timer->OnTimerExpired.connect([](const Timer * const&) { TimerProc(); });
l_Timer->Start(); l_Timer->Start();

View File

@ -24,7 +24,7 @@ void TimePeriod::Start(bool runtimeCreated)
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, [this]() { boost::call_once(once, [this]() {
l_UpdateTimer = new Timer(); l_UpdateTimer = Timer::Create();
l_UpdateTimer->SetInterval(300); l_UpdateTimer->SetInterval(300);
l_UpdateTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateTimerHandler(); }); l_UpdateTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateTimerHandler(); });
l_UpdateTimer->Start(); l_UpdateTimer->Start();

View File

@ -115,7 +115,7 @@ void IcingaDB::Start(bool runtimeCreated)
}); });
m_Rcon->Start(); m_Rcon->Start();
m_StatsTimer = new Timer(); m_StatsTimer = Timer::Create();
m_StatsTimer->SetInterval(1); m_StatsTimer->SetInterval(1);
m_StatsTimer->OnTimerExpired.connect([this](const Timer * const&) { PublishStatsTimerHandler(); }); m_StatsTimer->OnTimerExpired.connect([this](const Timer * const&) { PublishStatsTimerHandler(); });
m_StatsTimer->Start(); m_StatsTimer->Start();
@ -195,6 +195,8 @@ void IcingaDB::Stop(bool runtimeRemoved)
<< m_HistoryBulker.Size() << " queued history queries."; << m_HistoryBulker.Size() << " queued history queries.";
} }
m_StatsTimer->Stop(true);
Log(LogInformation, "IcingaDB") Log(LogInformation, "IcingaDB")
<< "'" << GetName() << "' stopped."; << "'" << GetName() << "' stopped.";

View File

@ -44,7 +44,7 @@ void NotificationComponent::Start(bool runtimeCreated)
SendNotificationsHandler(checkable, type, cr, author, text); SendNotificationsHandler(checkable, type, cr, author, text);
}); });
m_NotificationTimer = new Timer(); m_NotificationTimer = Timer::Create();
m_NotificationTimer->SetInterval(5); m_NotificationTimer->SetInterval(5);
m_NotificationTimer->OnTimerExpired.connect([this](const Timer * const&) { NotificationTimerHandler(); }); m_NotificationTimer->OnTimerExpired.connect([this](const Timer * const&) { NotificationTimerHandler(); });
m_NotificationTimer->Start(); m_NotificationTimer->Start();
@ -52,6 +52,8 @@ void NotificationComponent::Start(bool runtimeCreated)
void NotificationComponent::Stop(bool runtimeRemoved) void NotificationComponent::Stop(bool runtimeRemoved)
{ {
m_NotificationTimer->Stop(true);
Log(LogInformation, "NotificationComponent") Log(LogInformation, "NotificationComponent")
<< "'" << GetName() << "' stopped."; << "'" << GetName() << "' stopped.";

View File

@ -88,7 +88,7 @@ void ElasticsearchWriter::Resume()
m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); }); m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); });
/* Setup timer for periodically flushing m_DataBuffer */ /* Setup timer for periodically flushing m_DataBuffer */
m_FlushTimer = new Timer(); m_FlushTimer = Timer::Create();
m_FlushTimer->SetInterval(GetFlushInterval()); m_FlushTimer->SetInterval(GetFlushInterval());
m_FlushTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushTimeout(); }); m_FlushTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushTimeout(); });
m_FlushTimer->Start(); m_FlushTimer->Start();
@ -117,6 +117,8 @@ void ElasticsearchWriter::Pause()
m_HandleStateChanges.disconnect(); m_HandleStateChanges.disconnect();
m_HandleNotifications.disconnect(); m_HandleNotifications.disconnect();
m_FlushTimer->Stop(true);
Flush(); Flush();
m_WorkQueue.Join(); m_WorkQueue.Join();
Flush(); Flush();

View File

@ -83,7 +83,7 @@ void GelfWriter::Resume()
m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); }); m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); });
/* Timer for reconnecting */ /* Timer for reconnecting */
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); });
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -112,7 +112,7 @@ void GelfWriter::Pause()
m_HandleNotifications.disconnect(); m_HandleNotifications.disconnect();
m_HandleStateChanges.disconnect(); m_HandleStateChanges.disconnect();
m_ReconnectTimer.reset(); m_ReconnectTimer->Stop(true);
try { try {
ReconnectInternal(); ReconnectInternal();

View File

@ -88,7 +88,7 @@ void GraphiteWriter::Resume()
m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); }); m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); });
/* Timer for reconnecting */ /* Timer for reconnecting */
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); });
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -107,7 +107,7 @@ void GraphiteWriter::Resume()
void GraphiteWriter::Pause() void GraphiteWriter::Pause()
{ {
m_HandleCheckResults.disconnect(); m_HandleCheckResults.disconnect();
m_ReconnectTimer.reset(); m_ReconnectTimer->Stop(true);
try { try {
ReconnectInternal(); ReconnectInternal();

View File

@ -91,7 +91,7 @@ void InfluxdbCommonWriter::Resume()
m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); }); m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); });
/* Setup timer for periodically flushing m_DataBuffer */ /* Setup timer for periodically flushing m_DataBuffer */
m_FlushTimer = new Timer(); m_FlushTimer = Timer::Create();
m_FlushTimer->SetInterval(GetFlushInterval()); m_FlushTimer->SetInterval(GetFlushInterval());
m_FlushTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushTimeout(); }); m_FlushTimer->OnTimerExpired.connect([this](const Timer * const&) { FlushTimeout(); });
m_FlushTimer->Start(); m_FlushTimer->Start();
@ -113,6 +113,7 @@ void InfluxdbCommonWriter::Pause()
Log(LogDebug, GetReflectionType()->GetName()) Log(LogDebug, GetReflectionType()->GetName())
<< "Processing pending tasks and flushing data buffers."; << "Processing pending tasks and flushing data buffers.";
m_FlushTimer->Stop(true);
m_WorkQueue.Enqueue([this]() { FlushWQ(); }, PriorityLow); m_WorkQueue.Enqueue([this]() { FlushWQ(); }, PriorityLow);
/* Wait for the flush to complete, implicitly waits for all WQ tasks enqueued prior to pausing. */ /* Wait for the flush to complete, implicitly waits for all WQ tasks enqueued prior to pausing. */

View File

@ -75,7 +75,7 @@ void OpenTsdbWriter::Resume()
ReadConfigTemplate(m_ServiceConfigTemplate, m_HostConfigTemplate); ReadConfigTemplate(m_ServiceConfigTemplate, m_HostConfigTemplate);
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); });
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -92,7 +92,7 @@ void OpenTsdbWriter::Resume()
void OpenTsdbWriter::Pause() void OpenTsdbWriter::Pause()
{ {
m_HandleCheckResults.disconnect(); m_HandleCheckResults.disconnect();
m_ReconnectTimer.reset(); m_ReconnectTimer->Stop(true);
Log(LogInformation, "OpentsdbWriter") Log(LogInformation, "OpentsdbWriter")
<< "'" << GetName() << "' paused."; << "'" << GetName() << "' paused.";

View File

@ -58,7 +58,7 @@ void PerfdataWriter::Resume()
CheckResultHandler(checkable, cr); CheckResultHandler(checkable, cr);
}); });
m_RotationTimer = new Timer(); m_RotationTimer = Timer::Create();
m_RotationTimer->OnTimerExpired.connect([this](const Timer * const&) { RotationTimerHandler(); }); m_RotationTimer->OnTimerExpired.connect([this](const Timer * const&) { RotationTimerHandler(); });
m_RotationTimer->SetInterval(GetRotationInterval()); m_RotationTimer->SetInterval(GetRotationInterval());
m_RotationTimer->Start(); m_RotationTimer->Start();
@ -70,7 +70,7 @@ void PerfdataWriter::Resume()
void PerfdataWriter::Pause() void PerfdataWriter::Pause()
{ {
m_HandleCheckResults.disconnect(); m_HandleCheckResults.disconnect();
m_RotationTimer.reset(); m_RotationTimer->Stop(true);
#ifdef I2_DEBUG #ifdef I2_DEBUG
//m_HostOutputFile << "\n# Pause the feature" << "\n\n"; //m_HostOutputFile << "\n# Pause the feature" << "\n\n";

View File

@ -244,7 +244,7 @@ void ApiListener::Start(bool runtimeCreated)
SyncLocalZoneDirs(); SyncLocalZoneDirs();
m_RenewOwnCertTimer = new Timer(); m_RenewOwnCertTimer = Timer::Create();
if (Utility::PathExists(GetIcingaCADir() + "/ca.key")) { if (Utility::PathExists(GetIcingaCADir() + "/ca.key")) {
RenewOwnCert(); RenewOwnCert();
@ -272,13 +272,13 @@ void ApiListener::Start(bool runtimeCreated)
Application::Exit(EXIT_FAILURE); Application::Exit(EXIT_FAILURE);
} }
m_Timer = new Timer(); m_Timer = Timer::Create();
m_Timer->OnTimerExpired.connect([this](const Timer * const&) { ApiTimerHandler(); }); m_Timer->OnTimerExpired.connect([this](const Timer * const&) { ApiTimerHandler(); });
m_Timer->SetInterval(5); m_Timer->SetInterval(5);
m_Timer->Start(); m_Timer->Start();
m_Timer->Reschedule(0); m_Timer->Reschedule(0);
m_ReconnectTimer = new Timer(); m_ReconnectTimer = Timer::Create();
m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ApiReconnectTimerHandler(); }); m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ApiReconnectTimerHandler(); });
m_ReconnectTimer->SetInterval(10); m_ReconnectTimer->SetInterval(10);
m_ReconnectTimer->Start(); m_ReconnectTimer->Start();
@ -288,18 +288,18 @@ void ApiListener::Start(bool runtimeCreated)
* Previous: 60s reconnect, 30s OA, 60s cold startup. * Previous: 60s reconnect, 30s OA, 60s cold startup.
* Now: 10s reconnect, 10s OA, 30s cold startup. * Now: 10s reconnect, 10s OA, 30s cold startup.
*/ */
m_AuthorityTimer = new Timer(); m_AuthorityTimer = Timer::Create();
m_AuthorityTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateObjectAuthority(); }); m_AuthorityTimer->OnTimerExpired.connect([](const Timer * const&) { UpdateObjectAuthority(); });
m_AuthorityTimer->SetInterval(10); m_AuthorityTimer->SetInterval(10);
m_AuthorityTimer->Start(); m_AuthorityTimer->Start();
m_CleanupCertificateRequestsTimer = new Timer(); m_CleanupCertificateRequestsTimer = Timer::Create();
m_CleanupCertificateRequestsTimer->OnTimerExpired.connect([this](const Timer * const&) { CleanupCertificateRequestsTimerHandler(); }); m_CleanupCertificateRequestsTimer->OnTimerExpired.connect([this](const Timer * const&) { CleanupCertificateRequestsTimerHandler(); });
m_CleanupCertificateRequestsTimer->SetInterval(3600); m_CleanupCertificateRequestsTimer->SetInterval(3600);
m_CleanupCertificateRequestsTimer->Start(); m_CleanupCertificateRequestsTimer->Start();
m_CleanupCertificateRequestsTimer->Reschedule(0); m_CleanupCertificateRequestsTimer->Reschedule(0);
m_ApiPackageIntegrityTimer = new Timer(); m_ApiPackageIntegrityTimer = Timer::Create();
m_ApiPackageIntegrityTimer->OnTimerExpired.connect([this](const Timer * const&) { CheckApiPackageIntegrity(); }); m_ApiPackageIntegrityTimer->OnTimerExpired.connect([this](const Timer * const&) { CheckApiPackageIntegrity(); });
m_ApiPackageIntegrityTimer->SetInterval(300); m_ApiPackageIntegrityTimer->SetInterval(300);
m_ApiPackageIntegrityTimer->Start(); m_ApiPackageIntegrityTimer->Start();
@ -331,6 +331,13 @@ void ApiListener::RenewOwnCert()
void ApiListener::Stop(bool runtimeDeleted) void ApiListener::Stop(bool runtimeDeleted)
{ {
m_ApiPackageIntegrityTimer->Stop(true);
m_CleanupCertificateRequestsTimer->Stop(true);
m_AuthorityTimer->Stop(true);
m_ReconnectTimer->Stop(true);
m_Timer->Stop(true);
m_RenewOwnCertTimer->Stop(true);
ObjectImpl<ApiListener>::Stop(runtimeDeleted); ObjectImpl<ApiListener>::Stop(runtimeDeleted);
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")

View File

@ -47,7 +47,7 @@ static void EnsureFrameCleanupTimer()
static boost::once_flag once = BOOST_ONCE_INIT; static boost::once_flag once = BOOST_ONCE_INIT;
boost::call_once(once, []() { boost::call_once(once, []() {
l_FrameCleanupTimer = new Timer(); l_FrameCleanupTimer = Timer::Create();
l_FrameCleanupTimer->OnTimerExpired.connect([](const Timer * const&) { ScriptFrameCleanupHandler(); }); l_FrameCleanupTimer->OnTimerExpired.connect([](const Timer * const&) { ScriptFrameCleanupHandler(); });
l_FrameCleanupTimer->SetInterval(30); l_FrameCleanupTimer->SetInterval(30);
l_FrameCleanupTimer->Start(); l_FrameCleanupTimer->Start();

View File

@ -11,13 +11,13 @@ BOOST_AUTO_TEST_SUITE(base_timer)
BOOST_AUTO_TEST_CASE(construct) BOOST_AUTO_TEST_CASE(construct)
{ {
Timer::Ptr timer = new Timer(); Timer::Ptr timer = Timer::Create();
BOOST_CHECK(timer); BOOST_CHECK(timer);
} }
BOOST_AUTO_TEST_CASE(interval) BOOST_AUTO_TEST_CASE(interval)
{ {
Timer::Ptr timer = new Timer(); Timer::Ptr timer = Timer::Create();
timer->SetInterval(1.5); timer->SetInterval(1.5);
BOOST_CHECK(timer->GetInterval() == 1.5); BOOST_CHECK(timer->GetInterval() == 1.5);
} }
@ -31,7 +31,7 @@ static void Callback(const Timer * const&)
BOOST_AUTO_TEST_CASE(invoke) BOOST_AUTO_TEST_CASE(invoke)
{ {
Timer::Ptr timer = new Timer(); Timer::Ptr timer = Timer::Create();
timer->OnTimerExpired.connect(&Callback); timer->OnTimerExpired.connect(&Callback);
timer->SetInterval(1); timer->SetInterval(1);
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(invoke)
BOOST_AUTO_TEST_CASE(scope) BOOST_AUTO_TEST_CASE(scope)
{ {
Timer::Ptr timer = new Timer(); Timer::Ptr timer = Timer::Create();
timer->OnTimerExpired.connect(&Callback); timer->OnTimerExpired.connect(&Callback);
timer->SetInterval(1); timer->SetInterval(1);