Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
087da87
IcingaDB: enqueue config runtime updates to the worker queue
yhabteab Oct 30, 2025
8d28f60
Revert "IcingaDB: suppress state sync until config sync finished"
yhabteab Oct 30, 2025
acbeed0
RedisConnection: simplify query prioritization logic
yhabteab Oct 31, 2025
5268482
RedisConnection: enhance `WriteQueueItem` & related usages
yhabteab Oct 31, 2025
0ce890f
Revert "CheckerComponent#CheckThreadProc(): also propagate next check…
yhabteab Nov 3, 2025
eb863fc
IcingaDB: subscribe to `OnNextCheckChanged` signal
yhabteab Nov 3, 2025
9df8332
IcingaDB: use polymorphism for queue entries
julianbrost Dec 5, 2025
b654aa2
Fix missing `olock` for dependency child registration
yhabteab Mar 4, 2026
fa95638
IcingaDB: remove unused `UpdateObjectAttrs` method
yhabteab Mar 10, 2026
6754fc2
Simplify `IcingaDB::PendingItemsThreadProc()` event loop
julianbrost Mar 11, 2026
6fc12b3
IcingaDB: put all queue related stuff into `icingadb:task_queue` name…
yhabteab Mar 12, 2026
744479e
IcingaDB: use key extractor for worker queue
julianbrost Mar 17, 2026
d87c21a
Inline `DequeueAndProcessOne` & don't process items out of order
yhabteab Mar 23, 2026
3d7e0c4
Reduce min queue item age from `1000ms` to `300ms`
yhabteab Mar 23, 2026
9e14b5c
Checker: never reschedule checkables with already running checks
yhabteab Sep 24, 2025
a6a9ba9
Checkable: update `next_check` ts in `ExecuteCheck` only if it's needed
yhabteab Sep 24, 2025
d6011dc
Introduce `OnRescheduleCheck` signal & make use of it where appropriate
yhabteab Sep 23, 2025
41056ce
Let IDO subscribe to `OnNextCheckChanged` signal
yhabteab Mar 23, 2026
58cdf2b
Drop the now superfluous `OnNextCheckUpdated` signal
yhabteab Sep 23, 2025
6d9c989
ClusterEvents: add special special handling for `SetNextCheck` events
yhabteab Sep 23, 2025
5988a4a
tests: raise `Concurrency` config in global app fixture
yhabteab Sep 25, 2025
0c00918
checker: make result timer interval configurable for testing
yhabteab Sep 25, 2025
774b93f
test: add basic checker scheduling test cases
yhabteab Sep 25, 2025
cc491af
Don't use wrong `schedule_start` for produced `cr`s
yhabteab Mar 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 31 additions & 19 deletions lib/checker/checkercomponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ void CheckerComponent::OnConfigLoaded()
Checkable::OnNextCheckChanged.connect([this](const Checkable::Ptr& checkable, const Value&) {
NextCheckChangedHandler(checkable);
});
Checkable::OnRescheduleCheck.connect([this](const Checkable::Ptr& checkable, double nextCheck) {
NextCheckChangedHandler(checkable, nextCheck);
});
}

void CheckerComponent::Start(bool runtimeCreated)
Expand All @@ -69,7 +72,7 @@ void CheckerComponent::Start(bool runtimeCreated)
m_Thread = std::thread([this]() { CheckThreadProc(); });

m_ResultTimer = Timer::Create();
m_ResultTimer->SetInterval(5);
m_ResultTimer->SetInterval(m_ResultTimerInterval);
m_ResultTimer->OnTimerExpired.connect([this](const Timer * const&) { ResultTimerHandler(); });
m_ResultTimer->Start();
}
Expand Down Expand Up @@ -136,16 +139,13 @@ void CheckerComponent::CheckThreadProc()

bool forced = checkable->GetForceNextCheck();
bool check = true;
bool notifyNextCheck = false;
double nextCheck = -1;

if (!forced) {
if (!checkable->IsReachable(DependencyCheckExecution)) {
Log(LogNotice, "CheckerComponent")
<< "Skipping check for object '" << checkable->GetName() << "': Dependency failed.";

check = false;
notifyNextCheck = true;
}

Host::Ptr host;
Expand Down Expand Up @@ -182,7 +182,6 @@ void CheckerComponent::CheckThreadProc()
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", nextCheck);

check = false;
notifyNextCheck = true;
}
}
}
Expand All @@ -201,23 +200,15 @@ void CheckerComponent::CheckThreadProc()
checkable->UpdateNextCheck();
}

if (notifyNextCheck) {
// Trigger update event for Icinga DB
Checkable::OnNextCheckUpdated(checkable);
}

lock.lock();

continue;
}


csi = GetCheckableScheduleInfo(checkable);

Log(LogDebug, "CheckerComponent")
<< "Scheduling info for checkable '" << checkable->GetName() << "' ("
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", checkable->GetNextCheck()) << "): Object '"
<< csi.Object->GetName() << "', Next Check: "
<< checkable->GetName() << "', Next Check: "
<< Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", csi.NextCheck)
<< " (" << std::fixed << std::setprecision(0) << csi.NextCheck << ").";

Expand All @@ -241,16 +232,16 @@ void CheckerComponent::CheckThreadProc()
*/
CheckerComponent::Ptr checkComponent(this);

Utility::QueueAsyncCallback([this, checkComponent, checkable]() { ExecuteCheckHelper(checkable); });
Utility::QueueAsyncCallback([this, checkComponent, checkable, csi]() { ExecuteCheckHelper(checkable, csi); });

lock.lock();
}
}

void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable)
void CheckerComponent::ExecuteCheckHelper(const Checkable::Ptr& checkable, const CheckableScheduleInfo& csi)
{
try {
checkable->ExecuteCheck(m_WaitGroup);
checkable->ExecuteCheck(m_WaitGroup, csi.NextCheck);
} catch (const std::exception& ex) {
CheckResult::Ptr cr = new CheckResult();
cr->SetState(ServiceUnknown);
Expand Down Expand Up @@ -342,7 +333,7 @@ CheckableScheduleInfo CheckerComponent::GetCheckableScheduleInfo(const Checkable
return csi;
}

void CheckerComponent::NextCheckChangedHandler(const Checkable::Ptr& checkable)
void CheckerComponent::NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck)
{
std::unique_lock<std::mutex> lock(m_Mutex);

Expand All @@ -357,7 +348,13 @@ void CheckerComponent::NextCheckChangedHandler(const Checkable::Ptr& checkable)

idx.erase(checkable);

CheckableScheduleInfo csi = GetCheckableScheduleInfo(checkable);
CheckableScheduleInfo csi;
if (nextCheck < 0) {
csi = GetCheckableScheduleInfo(checkable);
} else {
csi.NextCheck = nextCheck;
csi.Object = checkable;
}
idx.insert(csi);

m_CV.notify_all();
Expand All @@ -376,3 +373,18 @@ unsigned long CheckerComponent::GetPendingCheckables()

return m_PendingCheckables.size();
}

/**
* Sets the interval in seconds for the result timer.
*
* The result timer periodically logs the number of pending and idle checkables
* as well as the checks per second rate. The default interval is 5 seconds.
*
* Note, this method must be called before the component is started to have an effect on the timer.
*
* @param interval Interval in seconds for the result timer.
*/
void CheckerComponent::SetResultTimerInterval(double interval)
{
m_ResultTimerInterval = interval;
}
40 changes: 22 additions & 18 deletions lib/checker/checkercomponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,25 @@ struct CheckableScheduleInfo
{
Checkable::Ptr Object;
double NextCheck;
};

/**
* @ingroup checker
*/
struct CheckableNextCheckExtractor
{
typedef double result_type;

/**
* @threadsafety Always.
* Get the index value for ordering in the multi-index container.
*
* This function returns a very large value for checkables that have a running check, effectively pushing
* them to the end of the ordering. This ensures that checkables with running checks are not prioritized
* for scheduling ahead of others. Rescheduling of such checkables is unnecessary because the checkable
* is going to reject this anyway if it notices that a check is already running, so avoiding unnecessary
* CPU load. Once the running check is finished, the checkable will be re-inserted into the set with its
* actual next check time as the index value.
*
* @return The index value for ordering in the multi-index container.
*/
double operator()(const CheckableScheduleInfo& csi)
[[nodiscard]] double Index() const
{
return csi.NextCheck;
if (Object->HasRunningCheck()) {
return std::numeric_limits<double>::max();
}
return NextCheck;
}
};

Expand All @@ -58,7 +62,7 @@ class CheckerComponent final : public ObjectImpl<CheckerComponent>
CheckableScheduleInfo,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<boost::multi_index::member<CheckableScheduleInfo, Checkable::Ptr, &CheckableScheduleInfo::Object> >,
boost::multi_index::ordered_non_unique<CheckableNextCheckExtractor>
boost::multi_index::ordered_non_unique<boost::multi_index::const_mem_fun<CheckableScheduleInfo, double, &CheckableScheduleInfo::Index>>
>
> CheckableSet;

Expand All @@ -70,12 +74,16 @@ class CheckerComponent final : public ObjectImpl<CheckerComponent>
unsigned long GetIdleCheckables();
unsigned long GetPendingCheckables();

void SetResultTimerInterval(double interval);

private:
std::mutex m_Mutex;
std::condition_variable m_CV;
bool m_Stopped{false};
std::thread m_Thread;

double m_ResultTimerInterval{5.0}; // Interval in seconds for the result timer.

CheckableSet m_IdleCheckables;
CheckableSet m_PendingCheckables;

Expand All @@ -85,14 +93,10 @@ class CheckerComponent final : public ObjectImpl<CheckerComponent>
void CheckThreadProc();
void ResultTimerHandler();

void ExecuteCheckHelper(const Checkable::Ptr& checkable);

void AdjustCheckTimer();
void ExecuteCheckHelper(const Checkable::Ptr& checkable, const CheckableScheduleInfo& csi);

void ObjectHandler(const ConfigObject::Ptr& object);
void NextCheckChangedHandler(const Checkable::Ptr& checkable);

void RescheduleCheckTimer();
void NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck = -1);

static CheckableScheduleInfo GetCheckableScheduleInfo(const Checkable::Ptr& checkable);
};
Expand Down
4 changes: 2 additions & 2 deletions lib/db_ido/dbevents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void DbEvents::StaticInitialize()
DbEvents::RemoveAcknowledgement(checkable);
});

Checkable::OnNextCheckUpdated.connect([](const Checkable::Ptr& checkable) { NextCheckUpdatedHandler(checkable); });
Checkable::OnNextCheckChanged.connect([](const Checkable::Ptr& checkable, const Value&) { NextCheckChangedHandler(checkable); });
Checkable::OnFlappingChanged.connect([](const Checkable::Ptr& checkable, const Value&) { FlappingChangedHandler(checkable); });
Checkable::OnNotificationSentToAllUsers.connect([](const Notification::Ptr& notification, const Checkable::Ptr& checkable,
const std::set<User::Ptr>&, const NotificationType&, const CheckResult::Ptr&, const String&, const String&,
Expand Down Expand Up @@ -119,7 +119,7 @@ void DbEvents::StaticInitialize()
}

/* check events */
void DbEvents::NextCheckUpdatedHandler(const Checkable::Ptr& checkable)
void DbEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable)
{
Host::Ptr host;
Service::Ptr service;
Expand Down
2 changes: 1 addition & 1 deletion lib/db_ido/dbevents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class DbEvents
static void AddLogHistory(const Checkable::Ptr& checkable, const String& buffer, LogEntryType type);

/* Status */
static void NextCheckUpdatedHandler(const Checkable::Ptr& checkable);
static void NextCheckChangedHandler(const Checkable::Ptr& checkable);
static void FlappingChangedHandler(const Checkable::Ptr& checkable);
static void LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable);

Expand Down
3 changes: 0 additions & 3 deletions lib/icinga/apiactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,6 @@ Dictionary::Ptr ApiActions::RescheduleCheck(

checkable->SetNextCheck(nextCheck);

/* trigger update event for DB IDO */
Checkable::OnNextCheckUpdated(checkable);

return ApiActions::CreateResult(200, "Successfully rescheduled check for object '" + checkable->GetName() + "'.");
}

Expand Down
Loading
Loading