Como systemd
lida com a morte dos filhos dos processos gerenciados?
Suponha que isso systemd
inicie o daemon foo
, que então inicia três outros daemons: bar1
, bar2
, e bar3
. Fará systemd
alguma coisa foo
se bar2
terminar inesperadamente? Pelo que entendi, no Service Management Facility (SMF) no Solaris foo
seria eliminado ou reiniciado se você não informasse startd
o contrário, alterando a propriedade ignore_error
. Comporta systemd
-se de maneira diferente?
Edição nº 1:
Eu escrevi um daemon de teste para testar systemd
o comportamento de. O daemon é chamado mother_daemon
porque gera filhos.
#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;
}
Isso é controlado com uma systemd
unidade chamada 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
A mother_daemon.service
unidade é controlada por mother_daemon.target
:
[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service
Quando executo sudo systemctl start mother_daemon.target
(depois sudo systemctl daemon-reload
), posso ver o daemon pai e os cinco daemons filhos.
Matar um dos filhos não tem efeito sobre os pais, mas matar os pais (e, assim, desencadear uma reinicialização) reinicia os filhos.
Parar mother_daemon.target
com sudo systemctl stop mother_daemon.target
acaba com as crianças também.
Acho que isso responde à minha pergunta.
Responder1
Isso não acontece.
O processo principal trata da morte de seus filhos, de forma normal.
Este é o mundo POSIX. Se o processo A bifurcou B e o processo B bifurcou C, D e E; então o processo B é o que vê o status SIGCHLD
e wait()
do término de C, D e E. O processo A não tem conhecimento do que acontece com C, D e E, e isso independe do systemd.
Para que A esteja ciente da terminação de C, D e E, duas coisas precisam acontecer.
- Um tem queregistre-se como um "subreaper". O systemd faz isso, assim como vários outros gerenciadores de serviços, incluindo o upstart e o nosh
service-manager
. - B tem que
exit()
. Serviços quetolamente, erroneamente e em vãotentem se "daemonizar" fazendo isso.
(É possível ser esperto com kevent()
os BSDs. Mas esta é uma questão do Linux.)
Responder2
systemd
tem o conceito de um processo principal. Na documentação do systemd, isso é chamado de "processo de serviço principal" ou simplesmente "processo principal".
Exemplo 4 noDocumentação systemd.servicedescreve que o processo principal é calculado quando Type=forking
.
A documentação Restart=
nos documentos systemd.servicedescrever as diferentes possibilidades de quando um serviço é iniciado em relação ao processo principal.
Aqui está o texto principal do "exemplo 4" vinculado acima:
O systemd considerará o serviço em processo de inicialização enquanto o programa original ainda estiver em execução. Depois que ele for encerrado com êxito e pelo menos um processo permanecer (e RemainAfterExit=no), o serviço será considerado iniciado.
Freqüentemente, um daemon tradicional consiste apenas em um processo. Portanto, se resta apenas um processo após o término do processo original, o systemd considerará esse processo como o processo principal do serviço. Nesse caso, a variável $MAINPID estará disponível em ExecReload=, ExecStop=, etc.
Caso reste mais de um processo, o systemd não será capaz de determinar o processo principal, portanto não assumirá que existe um. Nesse caso, $MAINPID não será expandido para nada. Porém, se o processo decidir escrever um arquivo PID tradicional, o systemd poderá ler o PID principal a partir daí. Por favor, defina PIDFile= adequadamente.