Support for application lifecycle message

Change-Id: I16db05bccb9ac9a2d18b949952e5ad6812b729cc
This commit is contained in:
Geir Horn 2024-04-19 09:39:33 +02:00
parent 58b37118fb
commit 58ec992fe3
2 changed files with 113 additions and 81 deletions

View File

@ -147,6 +147,42 @@ void MetricUpdater::UpdateMetricValue(
}
}
// --------------------------------------------------------------------------
// Application lifcycle
// --------------------------------------------------------------------------
//
// When the lifecycle message is received, the state is just recorded in the
// state variable.
void MetricUpdater::LifecycleHandler(
const ApplicationLifecycle & TheState,
const Address TheLifecycleTopic )
{
Theron::ConsoleOutput Output;
ApplicationState = TheState;
Output << "Application state updated: " << std::endl
<< TheState.dump(2) << std::endl;
}
// The message handler used the conversion operator to read out the state
// carried in the message. It is based on having a static map from the textual
// representation of the state to the enumeration.
MetricUpdater::ApplicationLifecycle::operator State() const
{
static std::map< std::string_view, State > LifecycleStates{
{"NEW", State::New},
{"READY", State::Ready},
{"DEPLOYING", State::Deploying},
{"RUNNING", State::Running},
{"FAILED", State::Failed}
};
return LifecycleStates.at( this->at("state").get< std::string >() );
}
// --------------------------------------------------------------------------
// SLO Violation Events
// --------------------------------------------------------------------------
@ -174,7 +210,7 @@ void MetricUpdater::SLOViolationHandler(
Output << "Metric Updater: SLO violation received " << std::endl
<< SeverityMessage.dump(2) << std::endl;
if( !ReconfigurationInProgress &&
if(( ApplicationState == ApplicationLifecycle::State::Running ) &&
( AllMetricValuesSet ||
(!MetricValues.empty() &&
std::ranges::none_of( std::views::values( MetricValues ),
@ -183,41 +219,17 @@ void MetricUpdater::SLOViolationHandler(
Send( Solver::ApplicationExecutionContext(
SeverityMessage.at(
MetricValueUpdate::Keys::TimePoint ).get< Solver::TimePointType >(),
MetricValues, true
MetricValues, true
), TheSolverManager );
AllMetricValuesSet = true;
ReconfigurationInProgress = true;
AllMetricValuesSet = true;
ApplicationState = ApplicationLifecycle::State::Deploying;
}
else
Output << "... failed to forward the application execution context (size: "
<< MetricValues.size() << ")" << std::endl;
}
// --------------------------------------------------------------------------
// Reconfigured application
// --------------------------------------------------------------------------
//
// When the reconfiguration message is received it is an indication tha the
// Optimiser Controller has reconfigured the application and that the
// application is running in the new configuration found by the solver.
// It is the event that is important m not the content of the message, and
// it is therefore only used to reset the ongoing reconfiguration flag.
void MetricUpdater::ReconfigurationDone(
const ReconfigurationMessage & TheReconfiguraton,
const Address TheReconfigurationTopic )
{
Theron::ConsoleOutput Output;
ReconfigurationInProgress = false;
Output << "Reconfiguration ongoing flag reset after receiving the following "
<< "message indicating that the previous reconfiguration was"
<< "completed: " << std::endl
<< TheReconfiguraton.dump(2) << std::endl;
}
// --------------------------------------------------------------------------
// Constructor and destructor
// --------------------------------------------------------------------------
@ -239,13 +251,13 @@ MetricUpdater::MetricUpdater( const std::string UpdaterName,
StandardFallbackHandler( Actor::GetAddress().AsString() ),
NetworkingActor( Actor::GetAddress().AsString() ),
MetricValues(), ValidityTime(0), AllMetricValuesSet(false),
TheSolverManager( ManagerOfSolvers ),
ReconfigurationInProgress( false )
ApplicationState( ApplicationLifecycle::State::New ),
TheSolverManager( ManagerOfSolvers )
{
RegisterHandler( this, &MetricUpdater::AddMetricSubscription );
RegisterHandler( this, &MetricUpdater::UpdateMetricValue );
RegisterHandler( this, &MetricUpdater::SLOViolationHandler );
RegisterHandler( this, &MetricUpdater::ReconfigurationDone );
RegisterHandler( this, &MetricUpdater::LifecycleHandler );
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
@ -254,7 +266,7 @@ MetricUpdater::MetricUpdater( const std::string UpdaterName,
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
ReconfigurationMessage::AMQTopic ),
ApplicationLifecycle::AMQTopic ),
GetSessionLayerAddress() );
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
@ -279,7 +291,7 @@ MetricUpdater::~MetricUpdater()
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
Theron::AMQ::NetworkLayer::TopicSubscription::Action::CloseSubscription,
ReconfigurationMessage::AMQTopic ),
ApplicationLifecycle::AMQTopic ),
GetSessionLayerAddress() );
Send( Theron::AMQ::NetworkLayer::TopicSubscription(

View File

@ -225,6 +225,74 @@ private:
void UpdateMetricValue( const MetricValueUpdate & TheMetricValue,
const Address TheMetricTopic );
// --------------------------------------------------------------------------
// Application lifecycle
// --------------------------------------------------------------------------
//
// There is a message from the Optimiser Controller when the status of the
// application changes. The state communicated in this message shows the
// current state of the application and decides how the Solver will act to
// SLO Violations detected.
class ApplicationLifecycle
: public Theron::AMQ::JSONTopicMessage
{
public:
// The topic for the reconfiguration finished messages is defined by the
// optimiser as the sender.
static constexpr std::string_view AMQTopic
= "eu.nebulouscloud.optimiser.controller.app_state";
// The state of the application goes from the the initial creation of
// the cluster to deployments covering reconfigurations. Note that there is
// no state indicating that the application has terminated.
enum class State
{
New, // Waiting for the utility evaluator
Ready, // The application is ready for deployment
Deploying, // The application is being deployed or redeployed
Running, // The application is running
Failed // The application is in an invalid state
};
// An arriving lifecycle message indicates a change in state and it is
// therefore a way to set a state variable directly from the message by
// a cast operator
operator State() const;
// Constructors and destructor
ApplicationLifecycle( void )
: JSONTopicMessage( AMQTopic )
{}
ApplicationLifecycle( const ApplicationLifecycle & Other )
: JSONTopicMessage( Other )
{}
virtual ~ApplicationLifecycle() = default;
};
// After starting a reconfiguration with an SLO Violation, one should not
// initiate another reconfiguration because the state may the possibly be
// inconsistent with the SLO Violation Detector belieivng that the old
// configuration is still in effect while the new configuration is being
// enacted. The application lifecycle state must therefore be marked as
// running before the another SLO Violation will trigger the next
// reconfiguration
ApplicationLifecycle::State ApplicationState;
// The handler for the lifecycle message simply updates this variable by
// setting it to the state received in the lifecycle message.
void LifecycleHandler( const ApplicationLifecycle & TheState,
const Address TheLifecycleTopic );
// --------------------------------------------------------------------------
// SLO violations
// --------------------------------------------------------------------------
@ -295,54 +363,6 @@ private:
const Address TheSolverManager;
// After the sending of the application's excution context, one should not
// initiate another reconfiguration because the state may the possibly be
// inconsistent with the SLO Violation Detector belieivng that the old
// configuration is still in effect while the new configuration is being
// enacted. It is therefore a flag that will be set by the SLO Violation
// handler indicating that a reconfiguration is ongoing.
bool ReconfigurationInProgress;
// When a reconfiguration has been enacted by the Optimiser Controller and
// a new configuration is confirmed to be running on the new platofrm, it
// will send a message to inform all other components that the
// reconfiguration has happened. The event is just the reception of the
// message and its content will not be processed, so there are no keys for
// the JSON map received.
class ReconfigurationMessage
: public Theron::AMQ::JSONTopicMessage
{
public:
// The topic for the reconfiguration finished messages is defined by the
// optimiser as the sender.
static constexpr std::string_view AMQTopic
= "eu.nebulouscloud.optimiser.controller.reconfiguration";
// Constructors
ReconfigurationMessage( void )
: JSONTopicMessage( AMQTopic )
{}
ReconfigurationMessage( const ReconfigurationMessage & Other )
: JSONTopicMessage( Other )
{}
virtual ~ReconfigurationMessage() = default;
};
// The handler for this message will actually not use its contents, but only
// note that the reconfiguration has been completed to reset the
// reconfiguration in progress flag allowing future SLO Violation Events to
// triger new reconfigurations.
void ReconfigurationDone( const ReconfigurationMessage & TheReconfiguraton,
const Address TheReconfigurationTopic );
// --------------------------------------------------------------------------
// Constructor and destructor
// --------------------------------------------------------------------------