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

Ich habe ein Python-Skript, das eine Warteschlange prüft und für jedes Element eine Aktion ausführt:

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

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

 # keepalivescript.sh if processidfile exists: if processid is running: exit, all ok run checkqueue.py write processid to processidfile 

Ich rufe das von einer Crontab an:

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

Solutions Collecting From Web of "Wie schreibe ich ein Bash-Skript, um einen process neu zu starten, wenn es stirbt?"

Vermeiden Sie PID-Dateien, Crons oder irgendetwas anderes, das versucht, processe auszuwerten, die nicht ihre Kinder sind.

Es gibt einen guten Grund, warum Sie in UNIX NUR auf Ihre Kinder warten können. Jede Methode (ps-Analyse, pgrep, Speichern einer PID, …), die versucht, das zu umgehen, ist errorshaft und hat klaffende Löcher darin. Sag einfach Nein .

Stattdessen benötigen Sie den process, der Ihren process als übergeordneten process überwacht. Was bedeutet das? Dies bedeutet, dass nur der process, der Ihren process startet , zuverlässig darauf warten kann, dass er endet. In bash ist das absolut trivial.

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

Der obige bash Code führt myserver in eine until Schleife. Die erste Zeile startet myserver und wartet darauf, dass es beendet wird. Wenn es endet, until seinen Ausgangsstatus überprüft. Wenn der Exit-Status 0 , bedeutet das, dass er ordnungsgemäß beendet wurde (was bedeutet, dass Sie ihn gebeten haben, sich irgendwie zu beenden, und das hat er erfolgreich getan). In diesem Fall wollen wir es nicht neu starten (wir haben es einfach heruntergefahren!). Wenn der Beendigungsstatus nicht 0 , wird der Schleifenkörper ausgeführt, der eine Fehlermeldung auf STDERR ausgibt und die Schleife nach 1 Sekunde erneut startet (zurück in Zeile 1).

Warum warten wir eine Sekunde? Denn wenn etwas mit der Startsequenz von myserver 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 davon die Belastung weg.

Alles, was Sie jetzt tun müssen, ist dieses Bash-Skript (asynchron, wahrscheinlich) zu starten, und es überwacht myserver und myserver es bei Bedarf neu. Wenn Sie den Monitor beim Systemstart starten wollen (Neustart des Servers), können Sie ihn im cron (1) Ihres Benutzers mit einer @reboot Regel @reboot . Öffnen Sie Ihre Cron-Regeln mit crontab :

 crontab -e 

Fügen Sie anschließend eine Regel zum Starten Ihres Monitorskripts hinzu:

 @reboot /usr/local/bin/myservermonitor 

Alternative; schau auf inittab (5) und / etc / inittab. Sie können dort eine Zeile hinzufügen, damit myserver auf einer bestimmten Init-Ebene startet und automatisch neu gespawnt wird.


Bearbeiten.

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

Bedenken Sie:

  1. PID-Recycling (Töten des falschen processes):

    • /etc/init.d/foo start : foo starten, foo ‘s PID nach /var/run/foo.pid
    • Eine Weile später: foo stirbt irgendwie.
    • Eine Weile später: jeder zufällige process, der startet (Call bar ), nimmt eine zufällige PID, stellen Sie sich vor, dass es foo ‘s alte PID nimmt.
    • Du /var/run/foo.pid , dass foo weg ist: /etc/init.d/foo/restart liest /var/run/foo.pid , überprüft, ob es noch lebt, findet bar , denkt, dass es foo , tötet es, startet ein neues foo .
  2. PID-Dateien werden veraltet. Sie müssen eine zu komplizierte (oder sollte ich sagen, nicht triviale) Logik verwenden, um zu überprüfen, ob die PID-Datei veraltet ist, und eine solche Logik ist wieder anfällig für 1. ..

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

  4. Es ist sinnlos Überkompilierung; Sehen Sie, wie einfach mein Beispiel oben ist. Kein Grund, dies zu komplizieren.

Siehe auch: Sind PID-Dateien immer noch errorshaft, wenn sie ‘richtig’ machen?

Apropos; noch schlimmer als PID-Dateien ist das Parsen von ps ! Tue das niemals.

  1. PS ist sehr unportabel. Während Sie es auf fast jedem UNIX-System finden; Die Argumente variieren stark, wenn Sie eine nicht standardmäßige Ausgabe wünschen. Und Standardausgabe ist NUR für den menschlichen Verzehr, nicht für Scripted Parsing!
  2. Parsing führt zu vielen falschen Ergebnissen. Nimm den ps aux | grep PID ps aux | grep PID Beispiel, und stellen Sie sich nun vor, dass jemand einen process mit einer Zahl irgendwo als Argument startet, die genauso ist wie die PID, mit der Sie Ihren Daemon anstarrten! Stellen Sie sich vor, zwei Leute starten eine X-Sitzung und Sie gräbeln nach X, um Ihre zu töten. Es sind nur alle Arten von schlecht.

Wenn Sie den process nicht selbst verwalten möchten; Es gibt einige vollkommen gute Systeme, die als Monitor für Ihre processe dienen. Schauen Sie sich zum Beispiel runit an.

Schauen Sie sich monit ( http://mmonit.com/monit/ ) an. Es handhabt Start, Stopp und Neustart Ihres Skripts und kann Health Checks durchführen und bei Bedarf neu starten.

Oder mache ein einfaches Skript:

 while true do /your/script sleep 1 done 

Der einfachste Weg ist die Verwendung von Flock-Dateien. Im 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 der Shell können Sie testen, ob es läuft:

 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 müssen Sie nicht testen, denn wenn es bereits läuft und Sie es neu starten, wird es mit 'other instance already running'

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

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

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

Aus der Dokumentation: http://mmonit.com/monit/documentation/monit.html#pid_testing

 Überprüfe den process checkqueue.py mit pidfile /var/run/checkqueue.pid
        wenn geändert pid dann exec "checkqueue_restart.sh"

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

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 ist auf der Suche nach einem Java-process, so dass ich jps verwenden kann, das ist viel konsistenter über Distributionen als ps
  • $INSTALLATION enthält genug von dem processpfad, der absolut eindeutig ist
  • Verwenden Sie Schlaf, während Sie auf den process warten, um Ressourcen zu verlieren.

Dieses Skript wird tatsächlich verwendet, um eine laufende Tomcat-Instanz herunterzufahren, die ich über die Befehlszeile herunterfahren (und auf sie warten möchte). Daher ist das Starten als untergeordneter process für mich keine Option.