So stoppen Sie alle von einem Dienst erzeugten untergeordneten Prozesse

So stoppen Sie alle von einem Dienst erzeugten untergeordneten Prozesse

Ich habe einen Dienst unter Ubuntu mit der folgenden Konfiguration laufen:

#/etc/init/my_service.conf

start on (local-filesystems and net-device-up IFACE=eth1)

respawn

exec python -u /opt/XYZ/my_prog.py 2>&1 \
                 | logger -t my_prog.py

Beim Beenden des Dienstes mit sudo service my_service stopwird der Python-Prozess nicht beendet. Das Beenden des übergeordneten Prozesses mit killbeendet den Python-Prozess ebenfalls nicht.

Wie beende ich den Dienst vollständig (also alle untergeordneten Prozesse)? Idealerweise würde ich die obige Konfigurationsdatei nicht ändern.

Antwort1

Idealerweise möchte ich die obige Konfigurationsdatei nicht ändern.

Hart im Nehmen! Es ist das Richtige.

Sie müssen Ihr execin ändern scriptund die Ausführung dieses Python-Programms in einem gegabelten Unterprozess als Teil einer Pipeline beenden. Diese ServerFault-Antworterklärt, wie man das in einem eingebetteten Shell-Skript macht. Ich würde nur eine Änderung am dort angegebenen Skript vornehmen, und zwar in der letzten Zeile:

exec python -u /opt/XYZ/my_prog.py 2>&1

Es gibt schließlich keinen wirklich guten Grund, nicht auch Standardfehler zu protokollieren.

Immer komplexere Verrenkungen, um mit der Verzweigung fertig zu werden, von expect daemonzu Umstellung auf systemd, übersehen den Punkt, dass das Richtige darin besteht,Verhindern Sie, dass der Daemon sich aufspaltet. Wenn der aktuelle Wirbel etwas Gutes mit sich bringt, dann ist es die erneute Bestätigung dafür, dass das, was IBM 1995 geschrieben und empfohlen hat, all die Jahre über richtig war.

Gewöhnen Sie sich an den GedankenKettenbeladungDaemons. Es gibt viele Toolsets, die solche Dinge vereinfachen. Gewöhnen Sie sich auch an den Gedanken, keine Shell-Skripte mehr zu verwenden. Es gibt viele Toolsets, die speziell für diese Arbeit entwickelt wurden und den Overhead von Shells eliminieren (was in der Ubuntu-Welt eine bekanntermaßen gute Idee ist).

Beispiel: Die Shell-Befehle in der ServerFault-Antwort können durch ein Skript ersetzt werden, dasexeclineDie Werkzeuge von Laurent Bercotdie so konzipiert sind, dass sie genau dies ohne Unterschalen und nicht verknüpfte FIFOs tun können:

#!/command/execlineb -PW
pipeline -w {
    logger -t my_prog.py
} 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py

die Sie dann einfach

exec /foo/this_execlineb_script

Mitmein noshWerkzeugsatz, es wäre analog dazu ein Skript mit folgendem Inhalt:

#!/usr/local/bin/nosh
pipe 
fdmove -c 2 1 
python -u /opt/XYZ/my_prog.py | logger -t my_prog.py

Alternativ könnte man diese Strophe auch direkt in die Upstart-Jobdefinition aufnehmen (mit einem Trick, um Shell-Metazeichen zu vermeiden, sodass Upstart keine Shell erzeugt):

exec /usr/local/bin/exec pipe --separator SPLIT fdmove -c 2 1 python -u /opt/XYZ/my_prog.py SPLIT logger -t my_prog.py

Weiterführende Literatur

Antwort2

Unter GNU/Linux gibt es normalerweise keine Möglichkeit, einen Dienst und alle von ihm erzeugten Kindprozesse zu stoppen, da Kindprozesse ihre PPID (Parent Process ID) ändern können. Die einzige Möglichkeit, dies herauszufinden, besteht darin,verfolgenDas System ruft Prozesse auf, wenn sie erstellt werden, und führt eine Liste dieser Prozesse.

Das Ubuntu-Init-System upstarttut dies nicht. Die Antwort auf Ihre Frage lautet also:es ist unmöglich-- unter Ubuntu -- ohne:

  1. Dieses Skript ändern;
  2. Genau wissen, welche Prozess-IDs von diesem Prozess erzeugt werden;
  3. Diese Prozess-IDs manuell im Auge behalten;
  4. Sie einzeln töten.

Deshalb sollten Sie eine Linux-Distribution verwenden, die läuftsystemd. Wie Sie sehen können, systemdbehält den Überblick über alle Kindprozesseund kann jeden von ihnen mit einem einzigen Befehl töten. So funktioniert die GNU/Linux-Systemadministrationsollte sein, aber weil systemd so neu ist und weil es „Not Invented Here“ (d. h., Canonical hat es nicht erfunden) ist, möchte Ubuntu es nicht verwenden.

Antwort3

Sie haben übersprungen dieerwartenStrophe. DieEmporkömmling Kochbuchgibt an:

Warnung

Diese Strophe ist äußerst wichtig: Lesen Sie diesen Abschnitt sorgfältig durch!

Upstart verfolgt die Prozess-ID, die seiner Meinung nach zu einem Job gehört. Wenn ein Job die Instanzstrophe angegeben hat, verfolgt Upstart die PIDs für jede einzelne Instanz dieses Jobs.

Wenn Sie die expect-Strophe nicht angeben, verfolgt Upstart den Lebenszyklus der ersten PID, die es in den exec- oder script-Strophen ausführt. Die meisten Unix-Dienste werden jedoch „daemonisiert“, d. h. sie erstellen einen neuen Prozess (mit fork(2)), der ein Kind des ursprünglichen Prozesses ist. Dienste führen häufig ein „doppeltes Fork“ durch, um sicherzustellen, dass sie keinerlei Verbindung zum ursprünglichen Prozess haben. (Beachten Sie, dass kein Dienst anfangs mehr als zweimal forkt, da dies keinen zusätzlichen Vorteil bringt.)

In diesem Fall muss Upstart über eine Möglichkeit verfügen, dies zu verfolgen. Sie können also expect fork oder expect daemon verwenden, wodurch Upstart mit ptrace(2) „Forks zählen“ kann.

Damit Upstart die endgültige Prozess-ID für einen Job bestimmen kann, muss es wissen, wie oft dieser Prozess fork(2) aufruft. Upstart selbst kann die Antwort auf diese Frage nicht kennen, da ein Daemon, sobald er läuft, eine Reihe von „Arbeitsprozessen“ aufspalten könnte, die sich selbst beliebig oft aufspalten könnten. Von Upstart kann in diesem Fall nicht erwartet werden, dass es weiß, welche PID die „Master“-PID ist, da es nicht weiß, ob überhaupt Arbeitsprozesse erstellt werden, geschweige denn, wie oft, oder wie oft der Prozess anfangs aufspaltet. Daher ist es notwendig, Upstart mitzuteilen, welche PID die „Master“- oder übergeordnete PID ist. Dies wird mithilfe der expect-Strophe erreicht.

Sie benötigen dies, da die von Ihnen verwendete Pipe |untergeordnete Prozesse erstellt. Sie finden dies im BuchFortgeschrittene Linux-Programmierungeine kurze Einleitung dazu, in der es heißt:

Beispielsweise veranlasst dieser Shell-Befehl die Shell, zwei Kindprozesse zu erzeugen, einen fürlsund eine fürweniger:

 $ ls | less

Was ich nicht weiß, ist, ob dies eine oder zwei Gabeln impliziert, so dass ich mit der Änderung der Zeile experimentieren würdeWiederauferstehungin Ihrem Code mit entweder

 expect fork
 respawn

oder

 expect daemon
 respawn

Ich glaube nicht, dass das erreicht werden kannnurmitsystemd, auch wenn mein Logo deutlich zeigt, dass ich ein Fan von binsystemd.

verwandte Informationen