it-swarm.com.de

Wie schreibe ich ein Bash-Skript, um einen Prozess neu zu starten, wenn er stirbt?

Ich habe ein python Skript, das eine Warteschlange überprüft und eine Aktion für jedes Element ausführt:

# checkqueue.py
while True:
  check_queue()
  do_something()

Wie schreibe ich ein Bash-Skript, das überprüft, ob es ausgeführt wird, und wenn nicht, starten Sie es. Ungefähr der folgende Pseudocode (oder vielleicht sollte er so etwas wie ps | grep?):

# keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile

Ich werde das von einer Crontab nennen:

# crontab
*/5 * * * * /path/to/keepalivescript.sh
208
Tom

Vermeiden Sie PID-Dateien, Cron-Dateien oder alles andere, das versucht, Prozesse zu bewerten, die nicht ihren Kindern gehören.

Es gibt einen guten Grund, warum Sie unter UNIX NUR auf Ihre Kinder warten können. Jede Methode (ps parsing, pgrep, Speichern einer PID, ...), die versucht, dies zu umgehen, ist fehlerhaft und weist Lücken auf. Sagen Sie einfach nein .

Stattdessen muss der Prozess, der Ihren Prozess überwacht, der übergeordnete Prozess sein. Was bedeutet das? Dies bedeutet, dass nur der Prozess, der startet Ihr Prozess zuverlässig auf das Ende warten kann. In Bash ist dies absolut trivial.

until myserver; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

Der obige Teil des Bash-Codes führt myserver in einer until -Schleife aus. Die erste Zeile beginnt mit myserver und wartet auf das Ende. Wenn es endet, überprüft until seinen Beendigungsstatus. Wenn der Exit-Status 0 Ist, bedeutet dies, dass das Programm ordnungsgemäß beendet wurde (was bedeutet, dass Sie es aufgefordert haben, das Programm herunterzufahren, und dies war auch erfolgreich). In diesem Fall möchten wir es nicht neu starten (wir haben es nur gebeten, herunterzufahren!). Wenn der Beendigungsstatus nicht0 Ist, führt until den Schleifenkörper aus, der eine Fehlermeldung auf STDERR ausgibt und die Schleife neu startet (zurück zu Zeile 1) ) nach 1 Sekunde.

Warum warten wir eine Sekunde? Denn wenn etwas mit der Startsequenz von myserver nicht stimmt und es sofort abstürzt, haben Sie eine sehr intensive Schleife des ständigen Neustarts und Absturzes in Ihren Händen. Der sleep 1 Nimmt die Belastung davon.

Jetzt müssen Sie nur noch dieses Bash-Skript starten (wahrscheinlich asynchron), und es überwacht myserver und startet es bei Bedarf neu. Wenn Sie den Monitor beim Booten starten möchten (damit der Server Neustarts "überlebt"), können Sie dies im cron (1) Ihres Benutzers mit einer @reboot - Regel planen. Öffnen Sie Ihre Cron-Regeln mit crontab:

crontab -e

Fügen Sie dann eine Regel hinzu, um Ihr Monitorskript zu starten:

@reboot /usr/local/bin/myservermonitor

Alternative; Schauen Sie sich inittab (5) und/etc/inittab an. Sie können dort eine Zeile einfügen, damit myserver ab einer bestimmten Init-Stufe beginnt und automatisch neu erzeugt wird.


Bearbeiten.

Lassen Sie mich einige Informationen hinzufügen, warum keine PID-Dateien verwendet werden sollen . Während sie sehr beliebt sind; Sie sind auch sehr fehlerhaft und es gibt keinen Grund, warum Sie es nicht einfach richtig machen würden.

Bedenken Sie:

  1. PID-Recycling (Beenden des falschen Prozesses):

    • /etc/init.d/foo start: Startet foo, schreibt die PID von foo in /var/run/foo.pid
    • Eine Weile später: foo stirbt irgendwie.
    • Eine Weile später: Jeder zufällige Prozess, der gestartet wird (nennen Sie ihn bar), benötigt eine zufällige PID. Stellen Sie sich vor, Sie nehmen die alte PID von foo.
    • Sie bemerken, dass foo weg ist: /etc/init.d/foo/restart Liest /var/run/foo.pid, Prüft, ob es noch lebt, findet bar, denkt, es ist foo, tötet es startet ein neues foo.
  2. PID-Dateien veralten. Sie benötigen eine überkomplizierte (oder nicht triviale) Logik, um zu überprüfen, ob die PID-Datei veraltet ist, und eine solche Logik ist erneut anfällig für 1..

  3. Was ist, wenn Sie nicht einmal über Schreibzugriff verfügen oder sich in einer schreibgeschützten Umgebung befinden?

  4. Es ist sinnlose Überkomplikation; sehen Sie, wie einfach mein Beispiel oben ist. Das muss man überhaupt nicht komplizieren.

Siehe auch: Sind die PID-Dateien immer noch fehlerhaft, wenn Sie es richtig machen?

Apropos; Noch schlimmer als PID-Dateien ist das Parsen von ps! Tun Sie dies niemals.

  1. ps ist sehr unportabel. Während Sie es auf fast jedem UNIX-System finden; Die Argumente sind sehr unterschiedlich, wenn Sie eine nicht standardmäßige Ausgabe wünschen. Und die Standardausgabe ist NUR für den menschlichen Verzehr bestimmt, nicht für das Parsen mit Skripten!
  2. Das Parsen von ps führt zu VIELEN Fehlalarmen. Nehmen Sie das Beispiel ps aux | grep PID Und stellen Sie sich vor, jemand startet irgendwo einen Prozess mit einer Zahl als Argument, die der PID entspricht, mit der Sie Ihren Dämon angestarrt haben! Stellen Sie sich zwei Personen vor, die eine X-Sitzung beginnen und nach X greifen, um Ihre zu töten. Es ist einfach alles Mögliche schlecht.

Wenn Sie den Prozess nicht selbst verwalten möchten; Es gibt einige sehr gute Systeme, die Ihre Prozesse überwachen. Schauen Sie sich zum Beispiel runit an.

586
lhunath

Schauen Sie sich monit ( http://mmonit.com/monit/ ) an. Es verwaltet das Starten, Stoppen und Neustarten Ihres Skripts und kann bei Bedarf Integritätsprüfungen und Neustarts durchführen.

Oder mache ein einfaches Skript:

while true
do
/your/script
sleep 1
done
24
Bernd

Der einfachste Weg, dies zu tun, ist die Verwendung von Flock-on-File. In Python Skript würden Sie tun

lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0): 
   sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()

In Shell können Sie tatsächlich testen, ob es ausgeführt wird:

if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then 
   echo 'it's not running'
   restart.
else
   echo -n 'it's already running with PID '
   cat /tmp/script.lock
fi

Aber natürlich musst du nicht testen, denn wenn es bereits läuft und du es neu startest, wird es mit 'other instance already running'

Wenn der Prozess abbricht, werden alle Dateideskriptoren geschlossen und alle Sperren werden automatisch entfernt.

8
vartec

Sie sollten monit verwenden, ein Standard-Unix-Tool, das verschiedene Dinge auf dem System überwachen und entsprechend reagieren kann.

Aus den Dokumenten: http://mmonit.com/monit/documentation/monit.html#pid_testing

 Überprüfe den Prozess checkqueue.py mit der PID-Datei /var/run/checkqueue.pid
 Wenn die PID geändert wird, führe "checkqueue_restart.sh" aus 

Sie können monit auch so konfigurieren, dass Sie per E-Mail benachrichtigt werden, wenn ein Neustart durchgeführt wird.

6
clofresh
if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
    restart_process
    # Write PIDFILE
    echo $! >$PIDFILE
fi
5
soulmerge

Ich bin mir nicht sicher, wie portabel es unter verschiedenen Betriebssystemen ist, aber Sie können überprüfen, ob Ihr System den Befehl 'run-one' enthält, d. H. "Man run-one". Insbesondere enthält dieser Befehlssatz 'run-one-constant', was genau das zu sein scheint, was benötigt wird.

Aus der Manpage:

run-One-Constant-Befehl [ARGS]

Hinweis: Natürlich kann dies aus Ihrem Skript heraus aufgerufen werden, aber es ist auch nicht mehr erforderlich, überhaupt ein Skript zu haben.

2
Daniel Bradley

Ich habe das folgende Skript mit großem Erfolg auf zahlreichen Servern verwendet:

pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
echo $INSTALLATION found at PID $pid 
while [ -e /proc/$pid ]; do sleep 0.1; done

anmerkungen:

  • Es wird nach einem Java) - Prozess gesucht, damit ich jps verwenden kann. Dies ist über Distributionen hinweg viel konsistenter als ps
  • $INSTALLATION enthält genug von dem Prozesspfad, der absolut eindeutig ist
  • Nutze den Schlaf, während du darauf wartest, dass der Prozess endet, und vermeide es, Ressourcen zu verschlingen :)

Dieses Skript wird tatsächlich verwendet, um eine laufende Instanz von Tomcat herunterzufahren, die ich über die Befehlszeile herunterfahren (und warten) möchte. Das Starten als untergeordneter Prozess ist daher für mich keine Option.

1
Kevin Wright