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.
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.
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
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);
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") {
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;
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();
}
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();
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;
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
{