¿Cómo se systemd
maneja la muerte de los hijos de los procesos gestionados?
Supongamos que eso systemd
inicia el demonio foo
, que luego lanza otros tres demonios: bar1
, bar2
y bar3
. ¿Hará systemd
algo foo
si bar2
termina inesperadamente? Según tengo entendido, bajo Service Management Facility (SMF) en Solaris foo
se cerraría o reiniciaría si no se indica startd
lo contrario cambiando la propiedad ignore_error
. ¿ systemd
Se comporta diferente?
Edición #1:
He escrito un demonio de prueba para probar systemd
el comportamiento. El demonio se llama mother_daemon
porque engendra niños.
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Hi! I'm going to fork and make 5 child processes!" << endl;
for (int i = 0; i < 5; i++)
{
pid_t pid = fork();
if (pid > 0)
{
cout << "I'm the parent process, and i = " << i << endl;
}
if (pid == 0)
{
// The following four lines rename the process to make it easier to keep track of with ps
int argv0size = strlen(argv[0]);
string childThreadName = "mother_daemon child thread PID: ";
childThreadName.append( to_string(::getpid()) );
strncpy(argv[0],childThreadName.c_str(),argv0size + 25);
cout << "I'm a child process, and i = " << i << endl;
pause();
// I don't want each child process spawning its own process
break;
}
}
pause();
return 0;
}
Esto se controla con una systemd
unidad llamada mother_daemon.service
:
[Unit]
Description=Testing how systemd handles the death of the children of a managed process
StopWhenUnneeded=true
[Service]
ExecStart=/home/my_user/test_program/mother_daemon
Restart=always
La mother_daemon.service
unidad está controlada por mother_daemon.target
:
[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service
Cuando ejecuto sudo systemctl start mother_daemon.target
(después sudo systemctl daemon-reload
) puedo ver el demonio principal y los cinco demonios secundarios.
Matar a uno de los hijos no tiene ningún efecto en el padre, pero matar al padre (y por lo tanto desencadenar un reinicio) sí reinicia a los hijos.
Terminando mother_daemon.target
con sudo systemctl stop mother_daemon.target
los niños también.
Creo que esto responde a mi pregunta.
Respuesta1
No es así.
El proceso principal maneja la muerte de sus hijos, de forma normal.
Este es el mundo POSIX. Si el proceso A ha bifurcado a B y el proceso B ha bifurcado a C, D y E; entonces el proceso B es el que ve el estado SIGCHLD
y wait()
desde la terminación de C, D y E. El proceso A no sabe lo que sucede con C, D y E, y esto es independiente del sistema.
Para que A sea consciente de que C, D y E terminan, tienen que suceder dos cosas.
- un tiene queregistrarse como "subreaper". systemd hace esto, al igual que otros administradores de servicios, incluidos advenedizo y nosh
service-manager
. - B tiene que hacerlo
exit()
. Servicios quetontamente, erróneamente y en vanotratar de "endemoniarse" ellos mismos hacen esto.
(Uno puede ser inteligente con kevent()
los BSD. Pero esta es una pregunta de Linux).
Respuesta2
systemd
tiene el concepto de proceso principal. En la documentación de systemd, esto se denomina "proceso de servicio principal" o simplemente "proceso principal".
Ejemplo 4 en eldocumentación de systemd.servicedescribe tiene el proceso principal se calcula cuando Type=forking
.
La documentación Restart=
en los documentos systemd.servicedescribir las diferentes posibilidades para cuando se inicia un servicio en relación con el proceso principal.
Aquí está el texto clave del "ejemplo 4" vinculado arriba:
systemd considerará que el servicio está en proceso de inicialización mientras el programa original aún se está ejecutando. Una vez que sale exitosamente y queda al menos un proceso (y RemainAfterExit=no), el servicio se considera iniciado.
A menudo, un demonio tradicional sólo consta de un proceso. Por lo tanto, si solo queda un proceso después de que finaliza el proceso original, systemd considerará ese proceso como el proceso principal del servicio. En ese caso, la variable $MAINPID estará disponible en ExecReload=, ExecStop=, etc.
En caso de que quede más de un proceso, systemd no podrá determinar el proceso principal, por lo que no asumirá que existe uno. En ese caso, $MAINPID no se expandirá a nada. Sin embargo, si el proceso decide escribir un archivo PID tradicional, systemd podrá leer el PID principal desde allí. Configure PIDFile= en consecuencia.