17 #ifndef LIB_WINSS_SUPERVISE_SUPERVISE_HPP_ 18 #define LIB_WINSS_SUPERVISE_SUPERVISE_HPP_ 25 #include "easylogging/easylogging++.hpp" 26 #include "../handle_wrapper.hpp" 27 #include "../windows_interface.hpp" 28 #include "../filesystem_interface.hpp" 29 #include "../wait_multiplexer.hpp" 30 #include "../not_owning_ptr.hpp" 31 #include "../environment.hpp" 32 #include "../path_mutex.hpp" 33 #include "../process.hpp" 34 #include "../utils.hpp" 36 namespace fs = std::experimental::filesystem;
43 std::chrono::system_clock::time_point
time;
44 std::chrono::system_clock::time_point
last;
94 template<
typename TMutex,
typename TProcess>
104 std::vector<winss::NotOwningPtr<winss::SuperviseListener>>
listeners;
106 bool waiting =
false;
112 if (mutex.HasLock()) {
116 if (!
FILESYSTEM.ChangeDirectory(service_dir)) {
120 <<
"' does not exist.";
121 multiplexer->
Stop(kFatalExitCode);
126 multiplexer->
Stop(kMutexTaken);
130 state.time = std::chrono::system_clock::now();
131 state.last = state.time;
134 state.initially_up =
false;
135 state.remaining_count = 0;
151 std::string timeout_finish =
FILESYSTEM.Read(kTimeoutFinishFile);
153 if (timeout_finish.empty()) {
154 return kCommandTimeout;
157 return std::strtoul(timeout_finish.data(),
nullptr, 10);
166 virtual bool Start(
const std::string& file_name) {
179 params.
env = &env_dir;
180 bool created = process.Create(params);
181 state.pid = process.GetProcessId();
191 if (state.remaining_count == 0) {
196 VLOG(2) <<
"Starting run process";
199 state.is_run_process =
true;
201 WINDOWS.SetEnvironmentVariable(kRunExitCodeEnvName,
nullptr);
202 if (Start(kRunFile)) {
205 this->Triggered(
false);
207 state.is_run_process =
true;
210 if (state.remaining_count > 0) {
211 state.remaining_count--;
226 VLOG(2) <<
"Starting finish process";
228 state.is_run_process =
false;
230 WINDOWS.SetEnvironmentVariable(kRunExitCodeEnvName,
231 std::to_string(state.exit_code).c_str());
233 if (Start(kFinishFile)) {
236 this->Triggered(
false);
238 DWORD timeout = GetFinishTimeout();
259 state.time = std::chrono::system_clock::now();
261 switch (notification) {
263 state.last = state.time;
266 state.last = state.time;
270 auto it = listeners.begin();
271 while (it != listeners.end()) {
272 if ((*it)->Notify(notification, state)) {
275 it = listeners.erase(it);
288 if (waiting && !timeout) {
294 DWORD wait = kBusyWait;
297 if (state.is_run_process) {
298 VLOG(2) <<
"Run process ended";
306 state.exit_code = kSignaledExitCode;
308 state.exit_code = process.GetExitCode();
311 if (!StartFinish()) {
320 VLOG(2) <<
"Finish process ended";
325 if (process.GetExitCode() == kDownExitCode) {
326 state.remaining_count = 0;
332 }
else if (!Complete()) {
335 wait = kRunFailedWait;
336 LOG(WARNING) <<
"Unable to spawn ./run - waiting 10 seconds";
344 if (restart && !Complete() && state.remaining_count != 0) {
345 VLOG(2) <<
"Waiting for: " << wait;
370 multiplexer->
Stop(0);
392 static const int kMutexTaken = 100;
393 static const int kFatalExitCode = 111;
394 static const int kSignaledExitCode = 256;
395 static const int kDownExitCode = 125;
396 static const DWORD kCommandTimeout = 5000;
397 static const DWORD kBusyWait = 1000;
398 static const DWORD kRunFailedWait = 10000;
400 static constexpr
const char kMutexName[10] =
"supervise";
401 static constexpr
const char kRunFile[4] =
"run";
403 static constexpr
const char kFinishFile[7] =
"finish";
404 static constexpr
const char kDownFile[5] =
"down";
405 static constexpr
const char kEnvDir[4] =
"env";
407 static constexpr
const char kTimeoutFinishFile[15] =
"timeout-finish";
409 static constexpr
const char kTimeoutGroup[10] =
"supervise";
411 static constexpr
const char kRunExitCodeEnvName[24] =
412 "SUPERVISE_RUN_EXIT_CODE";
421 const fs::path& service_dir) : multiplexer(multiplexer),
422 mutex(service_dir, kMutexName), service_dir(service_dir) {
423 state.is_run_process =
true;
425 state.initially_up =
true;
427 state.remaining_count = -1;
459 listeners.push_back(listener);
466 if (!mutex.HasLock() || exiting) {
470 VLOG(3) <<
"Start supervised process if not started";
471 state.remaining_count = -1;
482 if (!mutex.HasLock() || exiting) {
486 VLOG(3) <<
"Run supervised process once";
488 state.remaining_count = 1;
491 state.remaining_count = 0;
499 if (!mutex.HasLock() || exiting) {
503 VLOG(3) <<
"Run supervised process at least once";
504 state.remaining_count = 0;
511 if (!mutex.HasLock()) {
515 state.remaining_count = 0;
523 if (!mutex.HasLock()) {
527 VLOG(3) <<
"Kill supervised process if not stopped";
528 if (state.is_up && state.is_run_process) {
537 if (!mutex.HasLock()) {
541 VLOG(3) <<
"Stop supervised process if not stopped";
542 if (state.is_up && state.is_run_process) {
551 if (!mutex.HasLock() || exiting) {
555 VLOG(3) <<
"Exit supervisor when supervised process goes down";
556 state.remaining_count = 0;
574 #endif // LIB_WINSS_SUPERVISE_SUPERVISE_HPP_ SuperviseTmpl(winss::NotOwningPtr< winss::WaitMultiplexer > multiplexer, const fs::path &service_dir)
Supervise constructor.
Definition: supervise.hpp:420
A wrapper for a Windows HANDLE.
Definition: handle_wrapper.hpp:39
The supervisor class template.
Definition: supervise.hpp:95
virtual void OnceAtMost()
Signals the supervisor to only run one if it is already running.
Definition: supervise.hpp:498
Run process has started.
Definition: supervise.hpp:60
Parameters to start a Windows process.
Definition: process.hpp:29
A directory where each file is an environment variable.
Definition: environment.hpp:58
bool is_run_process
Definition: supervise.hpp:45
#define WINDOWS
Definition: windows_interface.hpp:25
DWORD pid
Definition: supervise.hpp:51
Unknown notification.
Definition: supervise.hpp:58
virtual void Up()
Signals the supervisor to go into the up state.
Definition: supervise.hpp:465
virtual void Init()
Initializes the supervisor.
Definition: supervise.hpp:111
virtual bool IsStopping() const
Gets if the multiplexer is stopping.
Definition: wait_multiplexer.cpp:201
virtual void Down()
Signals the supervisor to be in the down state.
Definition: supervise.hpp:510
virtual void Stop()
Signal the supervisor to exit.
Definition: supervise.hpp:382
std::chrono::system_clock::time_point time
Definition: supervise.hpp:43
virtual bool Complete()
Tests exiting value.
Definition: supervise.hpp:362
virtual void AddStopCallback(Callback callback)
Add a stop callback.
Definition: wait_multiplexer.cpp:60
Definition: case_ignore.hpp:23
int up_count
Definition: supervise.hpp:48
Supervisor starting.
Definition: supervise.hpp:59
bool is_up
Definition: supervise.hpp:46
std::vector< winss::NotOwningPtr< winss::SuperviseListener > > listeners
The supervisor listeners.
Definition: supervise.hpp:104
virtual void AddTimeoutCallback(DWORD timeout, Callback callback, std::string group="")
Add a timeout item which given the timeout period will call the callback if it is not removed before ...
Definition: wait_multiplexer.cpp:50
virtual void AddTriggeredCallback(const winss::HandleWrapper &handle, TriggeredCallback callback)
Add a triggered callback for when an event happens on the given handle.
Definition: wait_multiplexer.cpp:43
virtual ~SuperviseListener()
Default virtual destructor.
Definition: supervise.hpp:85
winss::NotOwningPtr< winss::WaitMultiplexer > multiplexer
The event multiplexer for the supervisor.
Definition: supervise.hpp:98
fs::path service_dir
The service directory.
Definition: supervise.hpp:101
virtual void Once()
Signals the supervisor to be in the up state and when the process exits then leave it down...
Definition: supervise.hpp:481
std::chrono::system_clock::time_point last
Definition: supervise.hpp:44
virtual void AddListener(winss::NotOwningPtr< winss::SuperviseListener > listener)
Adds a supervisor listener to the list of listeners.
Definition: supervise.hpp:457
virtual void Triggered(bool timeout)
Event triggered handler.
Definition: supervise.hpp:287
The state of the supervisor.
Definition: supervise.hpp:42
int remaining_count
Definition: supervise.hpp:49
virtual bool StartFinish()
Starts the finish file process.
Definition: supervise.hpp:225
int exit_code
Definition: supervise.hpp:50
Supervisor exiting.
Definition: supervise.hpp:64
winss::Environment * env
The process environment.
Definition: process.hpp:36
Run process has ended.
Definition: supervise.hpp:61
virtual DWORD GetFinishTimeout() const
Gets the finish timeout value.
Definition: supervise.hpp:150
A HANDLE wait multiplexer.
Definition: wait_multiplexer.hpp:70
virtual void Stop(int code)
Stops the multiplexer with the given code if one has not already been set.
Definition: wait_multiplexer.cpp:189
virtual void NotifyAll(winss::SuperviseNotification notification)
Notify all the listeners with the given event.
Definition: supervise.hpp:258
virtual void AddInitCallback(Callback callback)
Add an initialization callback.
Definition: wait_multiplexer.cpp:37
#define FILESYSTEM
Definition: filesystem_interface.hpp:26
TProcess process
The supervised process.
Definition: supervise.hpp:100
The supervisor listener.
Definition: supervise.hpp:70
Definition: supervise.hpp:62
Permanent failure.
Definition: supervise.hpp:63
SuperviseNotification
The supervisor events which can occur.
Definition: supervise.hpp:57
virtual bool StartRun()
Starts the run file process.
Definition: supervise.hpp:190
SuperviseTmpl< winss::PathMutex, winss::Process > Supervise
Concrete supervise implementation.
Definition: supervise.hpp:571
TMutex mutex
The supervisor global mutex.
Definition: supervise.hpp:99
virtual bool RemoveTimeoutCallback(std::string group)
Removes the timeout call back for the given group.
Definition: wait_multiplexer.cpp:77
virtual void Kill()
Kills the supervised process.
Definition: supervise.hpp:522
virtual void Exit()
Signals the supervisor to exit.
Definition: supervise.hpp:550
virtual bool Start(const std::string &file_name)
Starts the process defined in the given file.
Definition: supervise.hpp:166
virtual void Term()
Sends a CTRL+BREAK to the supervised process.
Definition: supervise.hpp:536
bool initially_up
Definition: supervise.hpp:47
virtual const SuperviseState & GetState() const
Gets the current supervisor state.
Definition: supervise.hpp:448
static std::string ExpandEnvironmentVariables(const std::string &value)
Expand the given string with environment variables.
Definition: utils.cpp:31