From 35a3a032d0af69fd1fc055f94e6c48e9c16164a8 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Mon, 12 Oct 2026 16:44:42 +0100 Subject: [PATCH 1/7] Add supervision to the new `Component` class --- .../src/process_group_manager/details/BUILD | 7 + .../details/component.cpp | 96 +++++- .../details/component.hpp | 28 +- .../details/component_UT.cpp | 279 ++++++++++++++++-- 4 files changed, 370 insertions(+), 40 deletions(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD b/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD index 479d4555e6..d73c145809 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD @@ -23,6 +23,10 @@ cc_library( visibility = ["//score/launch_manager/src/daemon/src/process_group_manager:__subpackages__"], deps = [ ":icomponent", + "//score/launch_manager/src/daemon/src/alive_monitor:ialive_supervision_handle", + "//score/launch_manager/src/daemon/src/alive_monitor:isupervision_factory", + "//score/launch_manager/src/daemon/src/common:log", + "//score/launch_manager/src/daemon/src/configuration:component_config", "//score/launch_manager/src/daemon/src/process_group_manager/details/force_stop_action:iforce_stop_action", "//score/launch_manager/src/daemon/src/process_group_manager/details/ready_condition:iready_condition", "//score/launch_manager/src/daemon/src/process_group_manager/details/start_action:istart_action", @@ -37,6 +41,9 @@ lm_cc_test( deps = [ ":component", ":mock_component", + "//score/launch_manager:error", + "//score/launch_manager/src/daemon/src/alive_monitor:mock_alive_supervision_handle", + "//score/launch_manager/src/daemon/src/alive_monitor:mock_supervision_factory", "//score/launch_manager/src/daemon/src/process_group_manager/details/force_stop_action:mock_force_stop_action", "//score/launch_manager/src/daemon/src/process_group_manager/details/ready_condition:mock_ready_condition", "//score/launch_manager/src/daemon/src/process_group_manager/details/start_action:mock_start_action", diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index 6c692fcddc..af1330602a 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -12,23 +12,57 @@ ********************************************************************************/ #include "score/mw/launch_manager/process_group_manager/details/component.hpp" +#include "score/mw/launch_manager/common/log.hpp" namespace score::mw::lifecycle::internal { +namespace +{ + +std::unique_ptr constructSupervision( + configuration::ComponentConfig& config, + ISupervisionFactory& supervision_factory) +{ + if (config.component_properties.application_profile.application_type != + configuration::ApplicationType::ReportingAndSupervised) + { + return nullptr; + } + + SCORE_LANGUAGE_FUTURECPP_ASSERT_DBG_MESSAGE( + app_profile.alive_supervision.has_value(), "Supervised component did not have alive supervision config"); + + LM_LOG_DEBUG() << "Setting up alive supervision for" << config.name; + std::unique_ptr handle = supervision_factory.constructSupervision( + IdentifierHash{config.name}, + config.deployment_config.sandbox.uid, + config.component_properties.application_profile.alive_supervision.value()); + if (!handle) + { + LM_LOG_ERROR() << "Failed to set up alive supervision for" << config.name; + return nullptr; + } + + config.deployment_config.environmental_variables.add("LCM_ALIVE_INTERFACE_PATH", handle->getConnectionId()); + return handle; +} + +} // namespace + Component::Component( const IStartAction& start_action, const IStopAction& stop_action, const IForceStopAction& force_stop_action, const IReadyCondition& ready_condition, - bool self_terminating, - IdentifierHash identifier) + ISupervisionFactory& supervision_factory, + configuration::ComponentConfig& config) : start_action_(start_action), stop_action_(stop_action), force_stop_action_(force_stop_action), ready_condition_(ready_condition), - self_terminating_(self_terminating), - identifier_(identifier), + config_(config), + supervision_handle_(constructSupervision(config, supervision_factory)), state_(TerminatedState{}) { } @@ -76,6 +110,9 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token) if (const StartingState* const starting = std::get_if(&state_)) { state_ = ReadyState{starting->handle_}; + + activateSupervision(); + return RequestState::kSuccess; } @@ -92,6 +129,8 @@ IComponent::RequestResult Component::deactivate(cpp::stop_token stop_token) (starting != nullptr) || (ready != nullptr), "Cannot deactivate component in a non-running state"); const Handle& handle = (starting != nullptr) ? starting->handle_ : ready->handle_; + deactivateSupervision(); + // If the component is still waiting for ready conditions, cancel that. if (starting != nullptr) { @@ -148,8 +187,7 @@ IComponent::RequestResult Component::tryHandleTermination(int32_t status) return RequestState::kWaiting; } - // Self-terminating components can accept terminations. - if (self_terminating_ && status == 0) + if (config_.component_properties.application_profile.is_self_terminating && status == 0) { return RequestState::kWaiting; } @@ -167,7 +205,7 @@ IComponent::RequestResult Component::tryHandleTermination(int32_t status) IdentifierHash Component::getIdentifier() const { - return identifier_; + return IdentifierHash{config_.name}; } bool Component::active() const @@ -176,4 +214,48 @@ bool Component::active() const return std::holds_alternative(state_); } +void Component::activateSupervision() const +{ + if (!supervision_handle_) + { + return; + } + + timespec timestamp{}; + + if (clock_gettime(CLOCK_MONOTONIC, ×tamp) != 0) + { + LM_LOG_ERROR() << config_.name << ": failed to get timestamp to activate supervision:" << strerror(errno); + return; + } + + if (!supervision_handle_->activateSupervision(timestamp)) + { + LM_LOG_ERROR() << config_.name << ": failed to activate supervision"; + return; + } +} + +void Component::deactivateSupervision() const +{ + if (!supervision_handle_) + { + return; + } + + timespec timestamp{}; + + if (clock_gettime(CLOCK_MONOTONIC, ×tamp) != 0) + { + LM_LOG_ERROR() << config_.name << ": failed to get timestamp to deactivate supervision: " << strerror(errno); + return; + } + + if (!supervision_handle_->deactivateSupervision(timestamp)) + { + LM_LOG_ERROR() << config_.name << ": failed to deactivate supervision"; + return; + } +} + } // namespace score::mw::lifecycle::internal diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp index 9f503fa644..e66c29401e 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp @@ -14,6 +14,9 @@ #ifndef SCORE_LCM_COMPONENT_HPP_INCLUDED #define SCORE_LCM_COMPONENT_HPP_INCLUDED +#include "score/mw/launch_manager/alive_monitor/ialive_supervision_handle.hpp" +#include "score/mw/launch_manager/alive_monitor/isupervision_factory.hpp" +#include "score/mw/launch_manager/configuration/component_config.hpp" #include "score/mw/launch_manager/process_group_manager/details/force_stop_action/iforce_stop_action.hpp" #include "score/mw/launch_manager/process_group_manager/details/icomponent.hpp" #include "score/mw/launch_manager/process_group_manager/details/ready_condition/iready_condition.hpp" @@ -29,20 +32,20 @@ namespace score::mw::lifecycle::internal class Component final : public IComponent { public: - /// @brief Creates a new component from the given actions. + /// @brief Creates a new component from its configuration and the given actions. /// @param start_action How to start the resource. /// @param stop_action How to gracefully stop the resource. /// @param force_stop_action How to forcefully stop the resource. /// @param ready_condition How to decide when the resource has finished its startup. - /// @param self_terminating Whether the resource is allowed to terminate on its own. - /// @param identifier Name of the component. + /// @param supervision_factory Factory used to construct alive supervision. + /// @param config Configuration of the component. Component( const IStartAction& start_action, const IStopAction& stop_action, const IForceStopAction& force_stop_action, const IReadyCondition& ready_condition, - bool self_terminating = false, - IdentifierHash identifier = IdentifierHash{}); + ISupervisionFactory& supervision_factory, + configuration::ComponentConfig& config); /// @brief Start the resource and set the component to active. /// @param stop_token Token which can be used to interrupt the activation. @@ -83,11 +86,12 @@ class Component final : public IComponent /// @brief How to decide when the resource has finished its startup. const IReadyCondition& ready_condition_; - /// @brief Whether the resource is allowed to terminate on its own. - const bool self_terminating_; + /// @brief Configuration of the component. + const configuration::ComponentConfig& config_; - /// @brief Name of the component. - const IdentifierHash identifier_; + /// @brief Alive supervision of the resource, or nullptr if it is not supervised. + // TODO: Maybe should be inside the state + const std::unique_ptr supervision_handle_; struct TerminatedState final { @@ -121,6 +125,12 @@ class Component final : public IComponent /// @brief The current state of the component. State state_; + + /// @brief Start alive supervision now, if the component is supervised. + void activateSupervision() const; + + /// @brief Stop alive supervision now, if the component is supervised. + void deactivateSupervision() const; }; } // namespace score::mw::lifecycle::internal diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp index bc43a0c760..a9cf91c542 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp @@ -11,11 +11,14 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +#include "score/mw/launch_manager/alive_monitor/mock_alive_supervision_handle.hpp" +#include "score/mw/launch_manager/alive_monitor/mock_supervision_factory.hpp" #include "score/mw/launch_manager/process_group_manager/details/component.hpp" #include "score/mw/launch_manager/process_group_manager/details/force_stop_action/mock_force_stop_action.hpp" #include "score/mw/launch_manager/process_group_manager/details/ready_condition/mock_ready_condition.hpp" #include "score/mw/launch_manager/process_group_manager/details/start_action/mock_start_action.hpp" #include "score/mw/launch_manager/process_group_manager/details/stop_action/mock_stop_action.hpp" +#include "score/mw/lifecycle/execution_error.h" #include #include #include @@ -57,7 +60,9 @@ TEST(ComponentTest, StartSucceeds) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); const auto result = component.activate(cpp::stop_token{}); @@ -70,7 +75,9 @@ TEST(ComponentTest, StartActionCalled) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); EXPECT_CALL(start_action, start(_)).WillOnce(Return(Result{mock_handle})); @@ -83,7 +90,9 @@ TEST(ComponentTest, StopActionCalled) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); EXPECT_CALL(stop_action, stop(_, _)) @@ -99,7 +108,9 @@ TEST(ComponentTest, DeactivateReturnsWaitingWhenStopActionReturnsWaiting) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); ON_CALL(stop_action, stop(_, _)).WillByDefault(Return(IComponent::RequestState::kWaiting)); @@ -117,7 +128,9 @@ TEST(ComponentTest, DeactivateReturnsSuccessWhenStopActionReturnsSuccess) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); ON_CALL(stop_action, stop(_, _)).WillByDefault(Return(IComponent::RequestState::kSuccess)); @@ -135,7 +148,9 @@ TEST(ComponentTest, ReadyConditionCalled) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); EXPECT_CALL(ready_condition, wait(_, _)) @@ -150,7 +165,9 @@ TEST(ComponentTest, TerminationDuringStartupInterruptsActivation) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); EXPECT_CALL(ready_condition, wait(_, _)).WillOnce(Invoke([&component](cpp::stop_token token, const Handle) { @@ -172,7 +189,9 @@ TEST(ComponentTest, StartSetsActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); static_cast(component.activate(cpp::stop_token{})); @@ -185,7 +204,9 @@ TEST(ComponentTest, StopClearsActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); static_cast(component.activate(cpp::stop_token{})); component.deactivate(cpp::stop_token{}); @@ -199,7 +220,9 @@ TEST(ComponentTest, CannotDeactivateInTerminatedState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); EXPECT_DEATH( { static_cast(component.deactivate(cpp::stop_token{})); }, @@ -212,7 +235,9 @@ TEST(ComponentTest, CannotActivateInReadyState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -228,7 +253,9 @@ TEST(ComponentTest, CannotActivateInTerminatingState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); ON_CALL(stop_action, stop(_, _)).WillByDefault(Return(IComponent::RequestState::kWaiting)); @@ -246,7 +273,9 @@ TEST(ComponentTest, CannotDeactivateInTerminatingState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); ON_CALL(stop_action, stop(_, _)).WillByDefault(Return(IComponent::RequestState::kWaiting)); @@ -265,7 +294,9 @@ TEST(ComponentTest, CannotActivateInFaultState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -282,7 +313,9 @@ TEST(ComponentTest, CannotDeactivateInFaultState) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -300,7 +333,10 @@ TEST(ComponentTest, SelfTerminatingExitZeroInReadyStateIsWaiting) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -317,7 +353,10 @@ TEST(ComponentTest, SelfTerminatingExitZeroInReadyStateIsActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -333,7 +372,10 @@ TEST(ComponentTest, SelfTerminatingExitNonZeroInReadyStateIsError) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -350,7 +392,10 @@ TEST(ComponentTest, SelfTerminatingExitNonZeroInReadyStateIsNotActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -366,7 +411,10 @@ TEST(ComponentTest, SelfTerminatingExitZeroInStartingStateIsWaiting) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -388,7 +436,10 @@ TEST(ComponentTest, SelfTerminatingExitZeroInStartingStateIsActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); EXPECT_CALL(ready_condition, wait(_, _)).WillOnce(Invoke([&](cpp::stop_token, const Handle) { @@ -407,7 +458,10 @@ TEST(ComponentTest, SelfTerminatingExitNonZeroInStartingStateIsError) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -429,7 +483,10 @@ TEST(ComponentTest, SelfTerminatingExitNonZeroInStartingStateIsNotActive) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition, true); + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.is_self_terminating = true; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); EXPECT_CALL(ready_condition, wait(_, _)).WillOnce(Invoke([&](cpp::stop_token, const Handle) { @@ -448,7 +505,9 @@ TEST(ComponentTest, SettingBothStopTokens) MockStopAction stop_action; MockForceStopAction force_stop_action; MockReadyCondition ready_condition; - Component component(start_action, stop_action, force_stop_action, ready_condition); + NiceMock factory; + configuration::ComponentConfig config; + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); cpp::stop_source stop_source{}; ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); @@ -467,5 +526,177 @@ TEST(ComponentTest, SettingBothStopTokens) EXPECT_FALSE(result.has_value()); } +TEST(ComponentTest, SupervisionConstructedFromConfig) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.name = "comp"; + config.deployment_config.sandbox.uid = 1000U; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + config.component_properties.application_profile.alive_supervision->reporting_cycle_ms = 50U; + + EXPECT_CALL( + factory, + constructSupervision( + IdentifierHash{"comp"}, 1000U, Field(&configuration::ComponentAliveSupervision::reporting_cycle_ms, 50U))) + .WillOnce(Return(ByMove(std::unique_ptr{}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); +} + +TEST(ComponentTest, NoSupervisionConstructedWhenUnsupervised) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = configuration::ApplicationType::Reporting; + + EXPECT_CALL(factory, constructSupervision(_, _, _)).Times(0); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + EXPECT_EQ(config.deployment_config.environmental_variables.size(), 0U); +} + +TEST(ComponentTest, AliveInterfacePathAddedToEnvironment) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + ON_CALL(*handle, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + ASSERT_EQ(config.deployment_config.environmental_variables.size(), 1U); + const auto& variable = *config.deployment_config.environmental_variables.begin(); + EXPECT_EQ(variable.key(), "LCM_ALIVE_INTERFACE_PATH"); + EXPECT_EQ(variable.value(), "/test_path"); +} + +TEST(ComponentTest, FailedSupervisionConstructionLeavesComponentUnsupervised) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + const auto result = component.activate(cpp::stop_token{}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(config.deployment_config.environmental_variables.size(), 0U); +} + +TEST(ComponentTest, SupervisionActivatedWhenReady) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + EXPECT_CALL(*supervision, activateSupervision(_)).WillOnce(Return(true)); + + static_cast(component.activate(cpp::stop_token{})); +} + +TEST(ComponentTest, SupervisionNotActivatedWhenStartFails) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{MakeUnexpected(ExecErrc::kGeneralError)})); + EXPECT_CALL(*supervision, activateSupervision(_)).Times(0); + + static_cast(component.activate(cpp::stop_token{})); +} + +TEST(ComponentTest, SupervisionDeactivatedBeforeStopAction) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + + static_cast(component.activate(cpp::stop_token{})); + + InSequence sequence; + EXPECT_CALL(*supervision, deactivateSupervision(_)).WillOnce(Return(true)); + EXPECT_CALL(stop_action, stop(_, _)).WillOnce(Return(IComponent::RequestState::kSuccess)); + + static_cast(component.deactivate(cpp::stop_token{})); +} + } // namespace } // namespace score::mw::lifecycle::internal From 38c59da81e8f82782e38cc2b0c896198bef46cc0 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Thu, 22 Oct 2026 09:07:56 +0100 Subject: [PATCH 2/7] Deactivate supervision immediately on termination --- .../details/component.cpp | 5 ++++ .../details/component_UT.cpp | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index af1330602a..20bd010120 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -178,6 +178,11 @@ IComponent::RequestResult Component::tryHandleTermination(int32_t status) (starting != nullptr) || (ready != nullptr), "Cannot handle termination in a non-running state"); Handle& handle = (starting != nullptr) ? starting->handle_ : ready->handle_; + if (ready != nullptr) + { + deactivateSupervision(); + } + // Invalidate the resource to prevent acting on something which is already gone. invalidate(handle); diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp index a9cf91c542..75474965d1 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp @@ -667,6 +667,36 @@ TEST(ComponentTest, SupervisionNotActivatedWhenStartFails) static_cast(component.activate(cpp::stop_token{})); } +TEST(ComponentTest, SupervisionDeactivatedImmediatelyOnTermination) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + + InSequence sequence; + EXPECT_CALL(*supervision, activateSupervision(_)).WillOnce(Return(true)); + EXPECT_CALL(*supervision, deactivateSupervision(_)).WillOnce(Return(true)); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + static_cast(component.activate(cpp::stop_token{})); + static_cast(component.tryHandleTermination(1)); + + // deactivate() is never called because there is nothing reading the event queue +} + TEST(ComponentTest, SupervisionDeactivatedBeforeStopAction) { MockStartAction start_action; From 2c819e278da3376f13536337f41ee90afe7dc2c4 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Thu, 22 Oct 2026 12:29:08 +0100 Subject: [PATCH 3/7] Fail de/activation if supervision returns an error --- .../details/component.cpp | 43 +++++++----- .../details/component.hpp | 4 +- .../details/component_UT.cpp | 66 +++++++++++++++++++ 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index 20bd010120..d21cd5eb0a 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -111,7 +111,11 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token) { state_ = ReadyState{starting->handle_}; - activateSupervision(); + if (!activateSupervision()) + { + state_ = FaultState{}; + return cpp::make_unexpected(ComponentError::kErrorAfterReady); + } return RequestState::kSuccess; } @@ -129,7 +133,11 @@ IComponent::RequestResult Component::deactivate(cpp::stop_token stop_token) (starting != nullptr) || (ready != nullptr), "Cannot deactivate component in a non-running state"); const Handle& handle = (starting != nullptr) ? starting->handle_ : ready->handle_; - deactivateSupervision(); + if (!deactivateSupervision()) + { + state_ = FaultState{}; + return cpp::make_unexpected(ComponentError::kErrorAfterReady); + } // If the component is still waiting for ready conditions, cancel that. if (starting != nullptr) @@ -178,14 +186,15 @@ IComponent::RequestResult Component::tryHandleTermination(int32_t status) (starting != nullptr) || (ready != nullptr), "Cannot handle termination in a non-running state"); Handle& handle = (starting != nullptr) ? starting->handle_ : ready->handle_; - if (ready != nullptr) - { - deactivateSupervision(); - } - // Invalidate the resource to prevent acting on something which is already gone. invalidate(handle); + if (ready != nullptr && !deactivateSupervision()) + { + state_ = FaultState{}; + return cpp::make_unexpected(ComponentError::kErrorAfterReady); + } + // Certain ready conditions can accept terminations. if (starting != nullptr && ready_condition_.tryHandleTermination(handle, status)) { @@ -219,11 +228,11 @@ bool Component::active() const return std::holds_alternative(state_); } -void Component::activateSupervision() const +bool Component::activateSupervision() const { if (!supervision_handle_) { - return; + return true; } timespec timestamp{}; @@ -231,21 +240,23 @@ void Component::activateSupervision() const if (clock_gettime(CLOCK_MONOTONIC, ×tamp) != 0) { LM_LOG_ERROR() << config_.name << ": failed to get timestamp to activate supervision:" << strerror(errno); - return; + return false; } if (!supervision_handle_->activateSupervision(timestamp)) { LM_LOG_ERROR() << config_.name << ": failed to activate supervision"; - return; + return false; } + + return true; } -void Component::deactivateSupervision() const +bool Component::deactivateSupervision() const { if (!supervision_handle_) { - return; + return true; } timespec timestamp{}; @@ -253,14 +264,16 @@ void Component::deactivateSupervision() const if (clock_gettime(CLOCK_MONOTONIC, ×tamp) != 0) { LM_LOG_ERROR() << config_.name << ": failed to get timestamp to deactivate supervision: " << strerror(errno); - return; + return false; } if (!supervision_handle_->deactivateSupervision(timestamp)) { LM_LOG_ERROR() << config_.name << ": failed to deactivate supervision"; - return; + return false; } + + return true; } } // namespace score::mw::lifecycle::internal diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp index e66c29401e..bf235b5834 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp @@ -127,10 +127,10 @@ class Component final : public IComponent State state_; /// @brief Start alive supervision now, if the component is supervised. - void activateSupervision() const; + [[nodiscard]] bool activateSupervision() const; /// @brief Stop alive supervision now, if the component is supervised. - void deactivateSupervision() const; + [[nodiscard]] bool deactivateSupervision() const; }; } // namespace score::mw::lifecycle::internal diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp index 75474965d1..fa44ef66a9 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp @@ -641,6 +641,37 @@ TEST(ComponentTest, SupervisionActivatedWhenReady) static_cast(component.activate(cpp::stop_token{})); } +TEST(ComponentTest, SupervisionActivationFailureFaultsComponent) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + EXPECT_CALL(*supervision, activateSupervision(_)).WillOnce(Return(false)); + + const auto result = component.activate(cpp::stop_token{}); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), IComponent::ComponentError::kErrorAfterReady); + EXPECT_FALSE(component.active()); + EXPECT_DEATH( + { static_cast(component.deactivate(cpp::stop_token{})); }, + "Cannot deactivate component in a non-running state"); +} + TEST(ComponentTest, SupervisionNotActivatedWhenStartFails) { MockStartAction start_action; @@ -718,6 +749,7 @@ TEST(ComponentTest, SupervisionDeactivatedBeforeStopAction) Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + ON_CALL(*supervision, activateSupervision(_)).WillByDefault(Return(true)); static_cast(component.activate(cpp::stop_token{})); @@ -728,5 +760,39 @@ TEST(ComponentTest, SupervisionDeactivatedBeforeStopAction) static_cast(component.deactivate(cpp::stop_token{})); } +TEST(ComponentTest, SupervisionDeactivationFailureFaultsComponent) +{ + MockStartAction start_action; + MockStopAction stop_action; + MockForceStopAction force_stop_action; + MockReadyCondition ready_condition; + NiceMock factory; + configuration::ComponentConfig config; + config.component_properties.application_profile.application_type = + configuration::ApplicationType::ReportingAndSupervised; + config.component_properties.application_profile.alive_supervision = configuration::ComponentAliveSupervision{}; + + auto handle = std::make_unique>(); + auto* supervision = handle.get(); + ON_CALL(*supervision, getConnectionId()).WillByDefault(Return(std::string_view{"/test_path"})); + ON_CALL(factory, constructSupervision(_, _, _)) + .WillByDefault(Return(ByMove(std::unique_ptr{std::move(handle)}))); + + Component component(start_action, stop_action, force_stop_action, ready_condition, factory, config); + ON_CALL(start_action, start(_)).WillByDefault(Return(Result{mock_handle})); + EXPECT_CALL(*supervision, activateSupervision(_)).WillOnce(Return(true)); + static_cast(component.activate(cpp::stop_token{})); + EXPECT_CALL(*supervision, deactivateSupervision(_)).WillOnce(Return(false)); + EXPECT_CALL(stop_action, stop(_, _)).Times(0); + + const auto result = component.deactivate(cpp::stop_token{}); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), IComponent::ComponentError::kErrorAfterReady); + EXPECT_FALSE(component.active()); + EXPECT_DEATH( + { static_cast(component.deactivate(cpp::stop_token{})); }, + "Cannot deactivate component in a non-running state"); +} + } // namespace } // namespace score::mw::lifecycle::internal From e2870ab4bb8d7ef10d8e09b49c8f8558f35640b4 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Fri, 23 Oct 2026 13:58:30 +0100 Subject: [PATCH 4/7] Remove `TODO` comment This does not make sense because the supervision is created once in the constructor, not when the state changes. --- .../src/daemon/src/process_group_manager/details/component.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp index bf235b5834..aaeeb909fb 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp @@ -90,7 +90,6 @@ class Component final : public IComponent const configuration::ComponentConfig& config_; /// @brief Alive supervision of the resource, or nullptr if it is not supervised. - // TODO: Maybe should be inside the state const std::unique_ptr supervision_handle_; struct TerminatedState final From cb0d0ac77b8485314376a26458211f08c7b6ae88 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Mon, 26 Oct 2026 11:54:18 +0000 Subject: [PATCH 5/7] Make `ApplicationType::StateManager` supervised --- .../details/component.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index d418d4bfb0..4b4f7b87c6 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -20,12 +20,28 @@ namespace score::mw::lifecycle::internal namespace { +using score::mw::lifecycle::internal::configuration::ApplicationType; + +bool isSupervised(const ApplicationType& application_type) noexcept +{ + switch (application_type) + { + case ApplicationType::Native: + case ApplicationType::Reporting: + return false; + case ApplicationType::ReportingAndSupervised: + case ApplicationType::StateManager: + return true; + } + + SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("All possible cases are covered"); +} + std::unique_ptr constructSupervision( configuration::ComponentConfig& config, ISupervisionFactory& supervision_factory) { - if (config.component_properties.application_profile.application_type != - configuration::ApplicationType::ReportingAndSupervised) + if (!isSupervised(config.component_properties.application_profile.application_type)) { return nullptr; } From ea614459db7efaecc46984be9c6590a4770772a8 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Mon, 26 Oct 2026 14:17:45 +0000 Subject: [PATCH 6/7] Require supervision when starting a supervised component --- .../daemon/src/process_group_manager/details/component.cpp | 7 +++++++ .../src/process_group_manager/details/component_UT.cpp | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index 4b4f7b87c6..336f14f30e 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -90,6 +90,13 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token) SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( std::holds_alternative(state_), "Cannot activate component in a running state"); + if (isSupervised(config_.component_properties.application_profile.application_type) && !supervision_handle_) + { + LM_LOG_ERROR() << config_.name << ": alive supervision is not set up"; + state_ = FaultState{}; + return RequestResult::kFailure; + } + const Result start_result = start_action_.start(stop_token); if (!start_result.has_value()) { diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp index 45606a002a..9b7fb70fc4 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component_UT.cpp @@ -586,7 +586,7 @@ TEST(ComponentTest, AliveInterfacePathAddedToEnvironment) EXPECT_EQ(variable.value(), "/test_path"); } -TEST(ComponentTest, FailedSupervisionConstructionLeavesComponentUnsupervised) +TEST(ComponentTest, FailedSupervisionConstructionFailsActivation) { MockStartAction start_action; MockStopAction stop_action; @@ -605,7 +605,7 @@ TEST(ComponentTest, FailedSupervisionConstructionLeavesComponentUnsupervised) const auto result = component.activate(cpp::stop_token{}); - EXPECT_EQ(result, IComponent::RequestResult::kSuccess); + EXPECT_EQ(result, IComponent::RequestResult::kFailure); EXPECT_EQ(config.deployment_config.environmental_variables.size(), 0U); } From 91a536ae19b63e776abbd1578e968311fd45cd00 Mon Sep 17 00:00:00 2001 From: Daniel Thwaites Date: Mon, 26 Oct 2026 16:24:14 +0000 Subject: [PATCH 7/7] Preserve handle state when supervision de/activation fails --- .../process_group_manager/details/component.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp index 336f14f30e..87b458eaf1 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp @@ -132,15 +132,16 @@ IComponent::RequestResult Component::activate(cpp::stop_token stop_token) // The state could change while the lock was released, so we have to check. if (const StartingState* const starting = std::get_if(&state_)) { - state_ = ReadyState{starting->handle_}; - - if (!activateSupervision()) + if (activateSupervision()) + { + state_ = ReadyState{starting->handle_}; + return RequestResult::kSuccess; + } + else { - state_ = FaultState{}; + state_ = FaultState{starting->handle_}; return RequestResult::kFailure; } - - return RequestResult::kSuccess; } SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("If stop was not requested, then state must still be StartingState"); @@ -158,7 +159,7 @@ IComponent::RequestResult Component::deactivate(cpp::stop_token stop_token) if (!deactivateSupervision()) { - state_ = FaultState{}; + state_ = FaultState{handle}; return RequestResult::kFailure; } @@ -203,7 +204,7 @@ IComponent::TerminationResult Component::tryHandleTermination(int32_t status) if (ready != nullptr && !deactivateSupervision()) { - state_ = FaultState{}; + state_ = FaultState{handle}; return TerminationResult::kFailure; }