From: Davin McCall Date: Sat, 2 Jan 2016 13:24:31 +0000 (+0000) Subject: Add "smooth-recovery" option for process services. X-Git-Tag: v0.01~67 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=f29c89045a1298b0031e4c8d273f82e662a2ad8e;p=oweals%2Fdinit.git Add "smooth-recovery" option for process services. A process service with smooth-recovery set will restart its process (if it dies unexpectedly) without bring the service itself down. I.e the service remains in STARTED state, and any dependents do not have to be brought down. --- diff --git a/README b/README index da74f25..883a2dc 100644 --- a/README +++ b/README @@ -82,12 +82,10 @@ Parameters are: type = process | scripted | internal command = ... -restart = yes | true | no | false logfile = ... onstart = ... depends-on = (service name) waits-for = (service name) -termsignal = HUP | INT | QUIT | USR1 | USR2 command = (external script or executable, and arguments) For a 'process' service, this is the process to run. @@ -95,7 +93,19 @@ command = (external script or executable, and arguments) stop-command = (external script or executable, and arguments) For a 'scripted' service, this command is run to stop the service. - + +restart = yes | true | no | false + Specifies whether the service should automatically restart if it becomes + stopped (for any reason, including being explicitly requested to stop). + +smooth-recovery = yes | true | no | false + For process services only. Specifies that, should the process die, it + can be restarted without bringing the service itself down. This means that + any dependent services do not need to be stopped/restarted. Such recovery + happens regardless of the "restart" setting (if smooth-recovery is enabled, + the service does not reach the stopped state when the process terminates + unexpectedly). + onstart = (internal commands) rw_ready - try again to open any logs, control socket etc that could not be opened previously due to a read-only filesystem. @@ -112,7 +122,7 @@ waits-for = (service name) for this service. Starting this service will automatically start the named service. -termsignal = (signal) +termsignal = HUP | INT | QUIT | USR1 | USR2 Specifies an additional signal to send to the process when requesting it to terminate (applies to 'process' services only). SIGTERM is always sent along with the specified signal, unless the 'nosigterm' setting is diff --git a/load_service.cc b/load_service.cc index c99cedd..845f5c2 100644 --- a/load_service.cc +++ b/load_service.cc @@ -217,9 +217,10 @@ ServiceRecord * ServiceSet::loadServiceRecord(const char * name) string logfile; OnstartFlags onstart_flags; int term_signal = -1; // additional termination signal + bool auto_restart = false; + bool smooth_recovery = false; string line; - bool auto_restart = false; ifstream service_file; service_file.exceptions(ios::badbit | ios::failbit); @@ -276,6 +277,10 @@ ServiceRecord * ServiceSet::loadServiceRecord(const char * name) string restart = read_setting_value(i, end); auto_restart = (restart == "yes" || restart == "true"); } + else if (setting == "smooth-recovery") { + string recovery = read_setting_value(i, end); + smooth_recovery = (recovery == "yes" || recovery == "true"); + } else if (setting == "type") { string type_str = read_setting_value(i, end); if (type_str == "scripted") { @@ -342,6 +347,7 @@ ServiceRecord * ServiceSet::loadServiceRecord(const char * name) rval->setStopCommand(stop_command, stop_command_offsets); rval->setLogfile(logfile); rval->setAutoRestart(auto_restart); + rval->setSmoothRecovery(smooth_recovery); rval->setOnstartFlags(onstart_flags); rval->setExtraTerminationSignal(term_signal); *iter = rval; diff --git a/service.cc b/service.cc index d7dd138..d893a6d 100644 --- a/service.cc +++ b/service.cc @@ -108,6 +108,14 @@ void ServiceRecord::handle_exit_status() noexcept if (service_state == ServiceState::STOPPING) { stopped(); } + else if (smooth_recovery) { + // TODO ensure a minimum time between restarts + // TODO if we are pinned-started then we should probably check + // that dependencies have started before trying to re-start the + // service process. + start_ps_process(); + return; + } else { forceStop(); } @@ -168,7 +176,9 @@ void ServiceRecord::process_child_status(struct ev_loop *loop, ev_io * stat_io, else { // exec() succeeded. if (sr->service_type == ServiceType::PROCESS) { - sr->started(); + if (sr->service_state != ServiceState::STARTED) { + sr->started(); + } if (sr->pid == -1) { // Somehow the process managed to complete before we even saw the status. sr->handle_exit_status(); diff --git a/service.h b/service.h index abed451..b890c32 100644 --- a/service.h +++ b/service.h @@ -163,8 +163,9 @@ class ServiceRecord OnstartFlags onstart_flags; - string logfile; /* log file name, empty string specifies /dev/null */ - bool auto_restart : 1; /* whether to restart this (process) if it dies unexpectedly */ + string logfile; // log file name, empty string specifies /dev/null + bool auto_restart : 1; // whether to restart this (process) if it dies unexpectedly + bool smooth_recovery : 1; // whether the service process can restart without bringing down service bool pinned_stopped : 1; bool pinned_started : 1; @@ -358,6 +359,11 @@ class ServiceRecord this->auto_restart = auto_restart; } + void setSmoothRecovery(bool smooth_recovery) noexcept + { + this->smooth_recovery = smooth_recovery; + } + // Set "on start" flags (commands) void setOnstartFlags(OnstartFlags flags) noexcept {