Wie wird systemd
mit dem Tod der untergeordneten Prozesse verwaltet?
Angenommen, das systemd
startet den Daemon foo
, der dann drei weitere Daemons startet: bar1
, bar2
, und bar3
. Wird systemd
etwas unternommen foo
, wenn bar2
es unerwartet beendet wird? Meines Wissens foo
würde es unter Service Management Facility (SMF) auf Solaris beendet oder neu gestartet, wenn Sie nicht startd
durch Ändern der Eigenschaft etwas anderes angeben ignore_error
. systemd
Verhält es sich anders?
Bearbeitung Nr. 1:
Ich habe einen Test-Daemon geschrieben, um systemd
das Verhalten von zu testen. Der Daemon wird aufgerufen, mother_daemon
weil er Kinder erzeugt.
#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;
}
Dies wird mit einer systemd
Einheit gesteuert, die heißt 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
Die Steuerung der mother_daemon.service
Einheit erfolgt über mother_daemon.target
:
[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service
sudo systemctl start mother_daemon.target
Wenn ich (nach ) ausführe sudo systemctl daemon-reload
, kann ich den übergeordneten Daemon und die fünf untergeordneten Daemons sehen.
Das Beenden eines der untergeordneten Elemente hat keine Auswirkung auf das übergeordnete Element. Das Beenden des übergeordneten Elements (und damit das Auslösen eines Neustarts) führt jedoch zum Neustarten der untergeordneten Elemente.
mother_daemon.target
Mit dem Aufhören sudo systemctl stop mother_daemon.target
sind auch die Kinder fertig.
Ich denke, das beantwortet meine Frage.
Antwort1
Das ist nicht der Fall.
Der Hauptprozess behandelt den Tod seiner untergeordneten Prozesse auf die normale Weise.
Dies ist die POSIX-Welt. Wenn Prozess A B geforkt hat und Prozess B C, D und E geforkt hat, dann sieht Prozess B den Status SIGCHLD
und wait()
die Beendigung von C, D und E. Prozess A weiß nicht, was mit C, D und E passiert, und dies ist unabhängig von systemd.
Damit A die Beendigung von C, D und E erkennt, müssen zwei Dinge geschehen.
- A musssich als „Subreaper“ registrieren. systemd macht dies, ebenso wie verschiedene andere Service-Manager, darunter Upstart und Nosh
service-manager
. - B muss
exit()
. Dienstleistungen, dietöricht, irrtümlich und vergeblichversuchen, sich dabei zu „dämonisieren“.
(Bei den BSDs kann man es schlau machen kevent()
. Aber das ist eine Linux-Frage.)
Antwort2
systemd
hat das Konzept eines Hauptprozesses. In der systemd-Dokumentation wird dies als „Hauptdienstprozess“ oder einfach als „Hauptprozess“ bezeichnet.
Beispiel 4 imsystemd.service-Dokumentationbeschreibt den Hauptprozess, der berechnet wird, wenn Type=forking
.
Die Dokumentation für Restart=
in den systemd.service-DokumentenBeschreiben Sie die verschiedenen Möglichkeiten, wann ein Dienst in Bezug auf den Hauptprozess gestartet wird.
Hier ist der Schlüsseltext aus dem oben verlinkten „Beispiel 4“:
systemd geht davon aus, dass der Dienst initialisiert wird, während das ursprüngliche Programm noch ausgeführt wird. Sobald es erfolgreich beendet wird und mindestens ein Prozess übrig bleibt (und RemainAfterExit=no), gilt der Dienst als gestartet.
Oft besteht ein herkömmlicher Daemon nur aus einem Prozess. Wenn also nach Beendigung des ursprünglichen Prozesses nur noch ein Prozess übrig ist, betrachtet systemd diesen Prozess als Hauptprozess des Dienstes. In diesem Fall ist die Variable $MAINPID in ExecReload=, ExecStop= usw. verfügbar.
Falls mehr als ein Prozess übrig bleibt, kann systemd den Hauptprozess nicht bestimmen und geht daher nicht davon aus, dass es einen gibt. In diesem Fall wird $MAINPID nicht erweitert. Wenn der Prozess jedoch beschließt, eine traditionelle PID-Datei zu schreiben, kann systemd die Haupt-PID von dort lesen. Bitte legen Sie PIDFile= entsprechend fest.