diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp index 6e3b8764b..536482b46 100644 --- a/lib/icinga/checkable-check.cpp +++ b/lib/icinga/checkable-check.cpp @@ -14,6 +14,7 @@ #include "base/convert.hpp" #include "base/utility.hpp" #include "base/context.hpp" +#include using namespace icinga; @@ -94,7 +95,7 @@ double Checkable::GetLastCheck() const return schedule_end; } -Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin) +Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const CheckResultProducer::Ptr& producer, const MessageOrigin::Ptr& origin) { using Result = Checkable::ProcessingResult; @@ -106,6 +107,9 @@ Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr if (!cr) return Result::NoCheckResult; + if (!producer) + return Result::NoCheckResult; + double now = Utility::GetTime(); if (cr->GetScheduleStart() == 0) @@ -134,6 +138,14 @@ Checkable::ProcessingResult Checkable::ProcessCheckResult(const CheckResult::Ptr cr->SetCheckSource(command_endpoint->GetName()); } + std::shared_lock producerLock (*producer, std::try_to_lock); + + if (!producerLock) { + // Discard the check result to not delay the current reload. + // We'll re-run the check immediately after the reload. + return Result::CheckableInactive; + } + /* agent checks go through the api */ if (command_endpoint && GetExtension("agent_check")) { ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/icinga/checkable-script.cpp b/lib/icinga/checkable-script.cpp index fe08f32d3..6d5e64d33 100644 --- a/lib/icinga/checkable-script.cpp +++ b/lib/icinga/checkable-script.cpp @@ -9,18 +9,18 @@ using namespace icinga; -static void CheckableProcessCheckResult(const CheckResult::Ptr& cr) +static void CheckableProcessCheckResult(const CheckResult::Ptr& cr, const CheckResultProducer::Ptr& producer) { ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); Checkable::Ptr self = vframe->Self; REQUIRE_NOT_NULL(self); - self->ProcessCheckResult(cr); + self->ProcessCheckResult(cr, producer); } Object::Ptr Checkable::GetPrototype() { static Dictionary::Ptr prototype = new Dictionary({ - { "process_check_result", new Function("Checkable#process_check_result", CheckableProcessCheckResult, { "cr" }, false) } + { "process_check_result", new Function("Checkable#process_check_result", CheckableProcessCheckResult, { "cr", "producer" }, false) } }); return prototype; diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp index fcfbca9b2..9c91a066b 100644 --- a/lib/icinga/checkable.hpp +++ b/lib/icinga/checkable.hpp @@ -12,6 +12,7 @@ #include "icinga/notification.hpp" #include "icinga/comment.hpp" #include "icinga/downtime.hpp" +#include "remote/crproducer.hpp" #include "remote/endpoint.hpp" #include "remote/messageorigin.hpp" #include @@ -119,7 +120,8 @@ public: CheckableInactive, NewerCheckResultPresent, }; - ProcessingResult ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrigin::Ptr& origin = nullptr); + + ProcessingResult ProcessCheckResult(const CheckResult::Ptr& cr, const CheckResultProducer::Ptr& producer, const MessageOrigin::Ptr& origin = nullptr); Endpoint::Ptr GetCommandEndpoint() const; diff --git a/lib/remote/CMakeLists.txt b/lib/remote/CMakeLists.txt index 2271abff6..b80b96067 100644 --- a/lib/remote/CMakeLists.txt +++ b/lib/remote/CMakeLists.txt @@ -13,6 +13,7 @@ set(remote_SOURCES apilistener.cpp apilistener.hpp apilistener-ti.hpp apilistener-configsync.cpp apilistener-filesync.cpp apilistener-authority.cpp apiuser.cpp apiuser.hpp apiuser-ti.hpp + crproducer.hpp configfileshandler.cpp configfileshandler.hpp configobjectslock.cpp configobjectslock.hpp configobjectutility.cpp configobjectutility.hpp diff --git a/lib/remote/crproducer.hpp b/lib/remote/crproducer.hpp new file mode 100644 index 000000000..0ee192e5f --- /dev/null +++ b/lib/remote/crproducer.hpp @@ -0,0 +1,34 @@ +/* Icinga 2 | (c) 2025 Icinga GmbH | GPLv2+ */ + +#pragma once + +#include "base/object.hpp" + +namespace icinga +{ + +/** + * A component that produces check results and hence is responsible for them, e.g. CheckerComponent. + * I.e. on its shutdown it has to clean up and/or wait for its own ongoing checks if any. + * + * @ingroup icinga + */ +class CheckResultProducer : virtual public Object +{ +public: + DECLARE_PTR_TYPEDEFS(CheckResultProducer); + + /** + * Requests to delay the producer shutdown (if any) for a CheckResult to be processed. + * + * @return Whether request was accepted. + */ + virtual bool try_lock_shared() noexcept = 0; + + /** + * Releases one semaphore slot acquired for CheckResult processing. + */ + virtual void unlock_shared() noexcept = 0; +}; + +}