Versuchen:
#!/bin/bash
_term() {
echo "Caught SIGTERM signal!"
kill -TERM "$child" 2>/dev/null
}
trap _term SIGTERM
echo "Doing some initial work...";
/bin/start/main/server --nodaemon &
child=$!
wait "$child"
Normalerweise bash
werden alle Signale ignoriert, während ein untergeordneter Prozess ausgeführt wird. Wenn Sie den Server mit starten, &
wird er im Hintergrund in das Jobsteuerungssystem der Shell eingefügt, wobei $!
die PID des Servers (zur Verwendung mit wait
und kill
) festgehalten wird . Der Anruf wait
wartet dann auf den Abschluss des Auftrags mit der angegebenen PID (dem Server) oder auf das Auslösen von Signalen .
Wenn die Shell empfängt SIGTERM
(oder der Server unabhängig beendet), wait
kehrt der Anruf zurück (beendet mit dem Beendigungscode des Servers oder mit der Signalnummer + 128, falls ein Signal empfangen wurde). Wenn die Shell anschließend SIGTERM empfangen hat, ruft sie _term
vor dem Beenden die als SIGTERM-Trap-Handler angegebene Funktion auf (in der das Signal bereinigt und manuell an den Serverprozess weitergegeben wird kill
).
wait
Aufruf dann benötigt wird?exec /bin/start/main/server --nodaemon
(in diesem Fall wird der Shell-Prozess durch den Server-Prozess ersetzt und Sie müssen keine Signale weitergeben), oder Sie verwenden/bin/start/main/server --nodaemon &
, aber diesexec
ist nicht wirklich sinnvoll._term()
Funktionwait "$child"
erneut ausführen. Dies kann erforderlich sein, wenn ein anderer überwachender Prozess darauf wartet, dass das Shell-SkriptEXIT
abstürzt, bevor es erneut gestartet wird , oder wenn Sie auch eine Bereinigung durchführen und es erst ausführen müssen, nachdem der untergeordnete Prozess abgeschlossen wurde.exec
oder Sie möchten Fallen aufstellen .Bash leitet Signale wie SIGTERM nicht an Prozesse weiter, auf die es gerade wartet. Wenn Sie Ihren Skript beenden wollen , indem in segueing Ihren Server (so dass es Signale und etwas anderes zu behandeln, als ob Sie den Server direkt begonnen hatten), sollten Sie verwenden
exec
, das wird die Schale ersetzen mit dem Prozess geöffnet wird :Wenn Sie die Schale um aus irgendeinem Grund halten müssen (dh. Sie müssen eine gewisse Bereinigung tun , nachdem der Server beendet), sollten Sie eine Kombination aus verwenden
trap
,wait
undkill
. Siehe die Antwort von SensorSmith .quelle
Andreas Veithen weist darauf hin, dass, wenn Sie nicht vom Anruf zurückkehren müssen (wie im Beispiel des OP), ein einfacher Aufruf über den
exec
Befehl ausreicht ( Antwort von @Stuart P. Bentley ). Andernfalls ist "traditionell"trap 'kill $CHILDPID' TERM
(@ cuonglms Antwort) ein Start, aber derwait
Aufruf kehrt tatsächlich zurück, nachdem der Trap-Handler ausgeführt wurde, was noch möglich ist, bevor der untergeordnete Prozess tatsächlich beendet wird. Daher ist ein "zusätzlicher" Anruf anwait
ratsam ( Antwort von @ user1463361 ).Dies ist zwar eine Verbesserung, es besteht jedoch immer noch eine Race-Bedingung, was bedeutet, dass der Prozess möglicherweise nie beendet wird (es sei denn, der Signalgeber versucht erneut, das TERM-Signal zu senden). Das Fenster der Sicherheitsanfälligkeit liegt zwischen der Registrierung des Trap-Handlers und der Aufzeichnung der PID des Kindes.
Das Folgende beseitigt diese Sicherheitsanfälligkeit (in Funktionen zur Wiederverwendung verpackt).
quelle
Die bereitgestellte Lösung funktioniert bei mir nicht, da der Prozess abgebrochen wurde, bevor der Wartebefehl tatsächlich beendet wurde. Ich fand diesen Artikel http://veithen.github.io/2014/11/16/sigterm-propagation.html , der letzte Schnipsel funktionierte gut in meinem Anwendungsfall, der in OpenShift mit Custom Sh Runner gestartet wurde. Das sh-Skript ist erforderlich, da ich die Fähigkeit haben muss, Thread-Dumps abzurufen, was unmöglich ist, wenn die PID des Java-Prozesses 1 ist.
quelle