Ich habe ein Python-Skript, das eine Warteschlange überprü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 ausgeführt wird, und wenn nicht, starte es. Etwa der folgende Pseudocode (oder sollte er vielleicht so etwas tun 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 einem Crontab nennen:
# crontab
*/5 * * * * /path/to/keepalivescript.sh
Antworten:
Vermeiden Sie PID-Dateien, Crones oder alles andere, was versucht, Prozesse zu bewerten, die nicht ihre Kinder sind.
Es gibt einen sehr 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 klaffende Löcher auf. Sag einfach nein .
Stattdessen muss der Prozess, der Ihren Prozess überwacht, der übergeordnete Prozess sein. Was bedeutet das? Dies bedeutet, dass nur der Prozess, der Ihren Prozess startet , zuverlässig auf das Ende warten kann. In Bash ist dies absolut trivial.
Der obige Bash-Code wird
myserver
in eineruntil
Schleife ausgeführt. Die erste Zeile beginntmyserver
und wartet auf das Ende. Wenn es endet,until
überprüft es seinen Exit-Status. Wenn der Exit-Status lautet0
, bedeutet dies, dass er ordnungsgemäß beendet wurde (was bedeutet, dass Sie ihn aufgefordert haben, ihn irgendwie herunterzufahren, und dies erfolgreich). In diesem Fall möchten wir es nicht neu starten (wir haben es nur gebeten, herunterzufahren!). Wenn der Exit-Status nicht lautet0
,until
wird der Schleifenkörper ausgeführt, der eine Fehlermeldung bei STDERR ausgibt und die Schleife (zurück zu Zeile 1) nach 1 Sekunde neu startet .Warum warten wir eine Sekunde? Denn wenn etwas mit der Startsequenz von nicht stimmt
myserver
und es sofort abstürzt, haben Sie eine sehr intensive Schleife von ständigem Neustart und Absturz an Ihren Händen. Dassleep 1
nimmt die Belastung davon weg.Jetzt müssen Sie nur noch dieses Bash-Skript starten (wahrscheinlich asynchron), und es wird
myserver
es nach Bedarf überwachen und neu starten. Wenn Sie den Monitor beim Booten starten möchten (damit der Server einen Neustart "überlebt"), können Sie ihn mit einer@reboot
Regel im Cron (1) Ihres Benutzers planen . Öffnen Sie Ihre Cron-Regeln mitcrontab
:Fügen Sie dann eine Regel hinzu, um Ihr Monitorskript zu starten:
Alternative; Schauen Sie sich inittab (5) und / etc / inittab an. Sie können dort eine Zeile hinzufügen,
myserver
um bei einer bestimmten Init-Ebene zu beginnen und automatisch neu zu erscheinen.Bearbeiten.
Lassen Sie mich einige Informationen hinzufügen, warum Sie keine PID-Dateien verwenden sollten. 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:
PID-Recycling (Tötung des falschen Prozesses):
/etc/init.d/foo start
: Startfoo
, schreibefoo
die PID in/var/run/foo.pid
foo
stirbt irgendwie.bar
), nimmt eine zufällige PID, stellen Sie sich vor, er nimmtfoo
die alte PID.foo
, dass es weg ist:/etc/init.d/foo/restart
liest/var/run/foo.pid
, prüft, ob es noch lebt, findetbar
, denktfoo
, tötet es, startet ein neuesfoo
.PID-Dateien sind veraltet. Sie benötigen eine überkomplizierte (oder sollte ich sagen, nicht triviale) Logik, um zu überprüfen, ob die PID-Datei veraltet ist und eine solche Logik erneut anfällig ist
1.
.Was ist, wenn Sie nicht einmal Schreibzugriff haben oder sich in einer schreibgeschützten Umgebung befinden?
Es ist sinnlose Überkomplikation; Sehen Sie, wie einfach mein Beispiel oben ist. Das muss man überhaupt nicht komplizieren.
Siehe auch: Sind PID-Dateien immer noch fehlerhaft, wenn sie richtig gemacht werden?
Apropos; Noch schlimmer als PID-Dateien ist das Parsen
ps
! Tu das niemals.ps
ist sehr unsportlich. Während Sie es auf fast jedem UNIX-System finden; Die Argumente variieren stark, wenn Sie eine nicht standardmäßige Ausgabe wünschen. Und die Standardausgabe ist NUR für den menschlichen Verzehr bestimmt, nicht für das Parsing per Skript!ps
führt zu einer Menge falsch positiver Ergebnisse . Nehmen Sie dasps aux | grep PID
Beispiel und stellen Sie sich nun vor, jemand startet irgendwo einen Prozess mit einer Zahl als Argument, das zufällig mit der PID übereinstimmt, mit der Sie Ihren Daemon 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 schlecht.Wenn Sie den Prozess nicht selbst verwalten möchten; Es gibt einige sehr gute Systeme, die als Monitor für Ihre Prozesse dienen. Schauen Sie sich zum Beispiel Runit an.
quelle
while true; do myprocess; done
jedoch, dass es jetzt keine Möglichkeit gibt, den Prozess zu stoppen.trap 'kill $(jobs -p)' EXIT; until myserver & wait; do sleep 1; done
Schauen Sie sich monit an ( http://mmonit.com/monit/ ). Es übernimmt das Starten, Stoppen und Neustarten Ihres Skripts und kann bei Bedarf Integritätsprüfungen und Neustarts durchführen.
Oder machen Sie ein einfaches Skript:
quelle
Der einfachste Weg, dies zu tun, ist die Verwendung von Flock-on-File. In Python-Skript würden Sie tun
In der Shell können Sie tatsächlich testen, ob es ausgeführt wird:
Aber natürlich müssen Sie nicht testen, denn wenn es bereits ausgeführt wird und Sie es neu starten, wird es mit beendet
'other instance already running'
Wenn der Prozess stirbt, werden alle Dateideskriptoren geschlossen und alle Sperren werden automatisch entfernt.
quelle
flock
... in der Tat zeigt die Manpage explizit, wie!exec {lock_fd}>/tmp/script.lock; flock -x "$lock_fd"
ist die Bash-Entsprechung zu Python und lässt die Sperre beibehalten (wenn Sie also einen Prozess ausführen, bleibt die Sperre so lange erhalten, bis dieser Prozess beendet wird).flock
ist der richtige Weg, aber Ihre Skripte sind falsch. Der einzige Befehl, den Sie in crontab setzen müssen, ist:flock -n /tmp/script.lock -c '/path/to/my/script.py'
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
Sie können monit auch so konfigurieren, dass Sie beim Neustart eine E-Mail erhalten.
quelle
quelle
ps ax|grep ...
. Sie können es einfach installieren oder eine Funktion dafür schreiben: function psgrep () {ps ax | grep -v grep | grep -q "$ 1"}Ich bin nicht sicher, wie portabel es zwischen Betriebssystemen ist, aber Sie können überprüfen, ob Ihr System den Befehl 'run-one' enthält, dh "man run-one". Insbesondere enthält dieser Befehlssatz "Run-One-Constant", was genau das zu sein scheint, was benötigt wird.
Von der Manpage:
Hinweis: Dies kann natürlich aus Ihrem Skript heraus aufgerufen werden, macht aber auch die Notwendigkeit eines Skripts überflüssig.
quelle
Ich habe das folgende Skript mit großem Erfolg auf zahlreichen Servern verwendet:
Anmerkungen:
$INSTALLATION
enthält genug von dem Prozesspfad, der völlig eindeutig istDieses Skript wird tatsächlich verwendet, um eine laufende Instanz von Tomcat herunterzufahren, die ich über die Befehlszeile herunterfahren (und warten) möchte. Daher ist es für mich einfach keine Option, sie als untergeordneten Prozess zu starten.
quelle
grep | awk
ist immer noch ein Antimuster - Sie möchtenawk "/$INSTALLATION/ { print \$1 }"
das Nutzlosegrep
in das Awk-Skript einbinden, das durch regulären Ausdruck selbst sehr gut Zeilen finden kann. Vielen Dank.Ich benutze dies für meinen npm-Prozess
quelle