So starten Sie das Python-Skript automatisch neu, wenn es beendet wird oder abstürzt

31

Ich führe mein Python-Skript im Hintergrund auf meinem Ubuntu-Rechner (12.04) wie folgt aus:

nohup python testing.py > test.out &

Nun ist es möglich, dass mein Vorgesetzter irgendwann Python scriptaus irgendeinem Grund sterben kann.

Ich denke also an eine Art cron agentIn-Bash-Shell-Skript, das mein übergeordnetes Python-Skript automatisch neu starten kann, wenn es aus irgendeinem Grund beendet wird.

Ist das möglich zu tun? Wenn ja, wie lässt sich dieses Problem am besten lösen?

AKTUALISIEREN:

Nach dem Erstellen der testing.confDatei wie folgt -

chdir /tekooz
exec python testing.py
respawn

Ich habe den Befehl sudo unterschritten, um ihn zu starten, aber ich kann nicht sehen, dass der Prozess mit ps ax hinterherläuft.

root@bx13:/bezook# sudo start testing
testing start/running, process 27794
root@bx13:/bezook# ps ax | grep testing.py
27806 pts/3    S+     0:00 grep --color=auto testing.py

Irgendeine Idee, warum px axe mir nichts zeigt? Und wie überprüfe ich, ob mein Programm läuft oder nicht?

Dies ist mein Python-Skript -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)
Arsenal
quelle

Antworten:

24

Unter Ubuntu (bis 14.04, 16.04 und später systemd verwenden) kann dazu upstart verwendet werden, besser als ein Cron-Job. Sie legen ein Konfigurationssetup an /etc/initund stellen sicher, dass Sie Respawn angeben

Es kann sich um eine minimale Datei handeln /etc/init/testing.conf(bearbeiten als root):

chdir /your/base/directory
exec python testing.py
respawn

Und Sie können testen mit /your/base/directory/testing.py:

from __future__ import print_function

import time

with open('/var/tmp/testing.log', 'a') as fp:
    print(time.time(), 'done', file=fp)
    time.sleep(3)

und beginne mit:

sudo start testing

und folge was passiert (in einem anderen Fenster) mit:

tail -f /var/tmp/testing.log

und hör auf mit:

sudo stop testing

Sie können auch hinzufügen [start on][2], dass der Befehl beim Systemstart gestartet wird.

Zelda
quelle
Wenn Sie einen Cron-Job verwenden, möchten Sie entweder Code für die robuste Verarbeitung von PID-Dateien implementieren oder finden. Sie möchten, dass Ihr Dienst / Skript / Daemon eine PID-Datei erstellt (normalerweise unter / var / run) und den Startcode überprüft, ob der Dateiinhalt veraltet ist (von einem abgebrochenen Prozess zurückgelassen). Es ist überraschend schwierig, diese Art von Code frei von Rassen und Eckfällen zu schreiben. stackoverflow.com/questions/788411/…
Jim Dennis
@Zelda: Danke für den Vorschlag. Ich bin neu in der Linux / Unix-Welt. Welche Art von Änderungen soll ich in der /etc/initDatei vornehmen ? Wenn Sie mir eine schrittweise Anleitung geben können, werde ich in der Lage sein, etwas zu lernen und das Richtige zu tun.
Arsenal
@Webby Ich habe die Antwort vollständiger gemacht. Wenn Sie keine Datei zur Ausgabe öffnen und Ihre Druckanweisungen neu schreiben möchten, können Sie etwas wie sys.stdout = open(file_name, 'w')am Anfang tun .
Zelda
Vielen Dank, Zelda. Vielen Dank für Ihre Hilfe. Ich habe die Frage mit einigen Details aktualisiert. Ich versuche dies zu tun, um zu sehen, ob meine testing.py ausgeführt wird oder nicht. Es zeigt mir nicht, ob sie ausgeführt wird oder nicht px ax | grep testing.py. Gibt es mir nichts zurück? Irgendeine Idee warum?
Arsenal
Sie sollten das Ganze in eine try / except-Klausel setzen und in eine Protokolldatei schreiben, welche Ausnahme generiert wurde und dass das Programm beendet wird. Möglicherweise funktioniert die print-Anweisung nicht, da sie nicht in stdout schreiben kann.
Zelda
20

Sie könnten auch einen eher schalenorientierten Ansatz wählen. Suchen Sie cronnach Ihrem Skript und starten Sie es erneut, wenn es stirbt.

  1. Erstellen Sie eine neue Crontab, indem Sie ausführen crontab -e. Dies öffnet ein Fenster Ihres bevorzugten Texteditors.

  2. Fügen Sie diese Zeile der gerade geöffneten Datei hinzu

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Speichern Sie die Datei und beenden Sie den Editor.

Sie haben gerade ein neues crontabSkript erstellt , das alle 5 Minuten ausgeführt wird und das Skript startet, sofern es nicht bereits ausgeführt wird. Sehen Sie sich hier ein nettes kleines Tutorial an cron. Die offiziellen Ubuntu-Dokumente cronsind hier .

Der aktuell ausgeführte Befehl pgrepdurchsucht laufende Prozesse nach der in der Befehlszeile angegebenen Zeichenfolge. pgrep foosucht nach einem benannten Programm foound gibt dessen Prozesskennung zurück . pgrep -fDurchsucht die gesamte Befehlszeile, die zum Starten des Programms verwendet wird, und nicht nur den Programmnamen (nützlich, da dies ein Python-Skript ist).

Das ||Symbol bedeutet "Tun Sie dies, wenn der vorherige Befehl fehlgeschlagen ist". Wenn Ihr Skript nicht ausgeführt pgrepwird, schlägt das fehl, da es nichts findet und Ihr Skript gestartet wird.

terdon
quelle
Vielen Dank. Aber ich bin neu in Linux und Unix. Weißt du nicht, wo Crontab ist? Ist das eine Datei auf meinem Ubuntu-Rechner?
Arsenal
@Webby siehe aktualisierte Antwort.
Terdon
Vielen Dank, Terdon. Ich kann diesen Befehl crontab -eaus dem Verzeichnis ausführen, in dem sich mein Python-Skript befindet. Richtig?
Arsenal
1
@Webby können Sie es von überall ausführen. cronist ein Scheduling-Daemon, ein Dienst, der im Hintergrund ausgeführt wird. Wenn sich Ihr Python-Skript nicht in Ihrem befindet $PATH(wenn Sie es nicht von überall aus starten können, sondern in seinem Verzeichnis sein müssen), verwenden Sie den vollständigen Pfad zum Skript wie in meiner aktualisierten Antwort.
Terdon
Vielen Dank. Jetzt macht es Sinn. Ich habe gerade eine neue crontab erstellt und die Datei bearbeitet, indem ich dieselbe einzelne Zeile hinzugefügt habe, aber für 1 Minute. Ich habe bereits ein Hello World Python-Skript erstellt, das sich dreht, während True als testing.py benannt ist. Nach dem Speichern der crontab-datei sollte es nach 1 minute automatisch die testing.py starten? Und dann überprüfen Sie alle 1 Minute, ob das Python-Skript ausgeführt wird oder nicht? Wenn ja, habe ich nach dem Speichern der crontab -e-Datei ps axe | grep testing.py und ich kann keinen Prozess dafür sehen?
Arsenal
6

Sie können das Testprogramm die Ausgabe mit einer Befehlszeilenoption umleiten lassen und dann ein einfaches Python-Skript verwenden, um das Programm auf unbestimmte Zeit neu zu starten:

import subprocess

while True:
    try:
        print subprocess.check_output(['python', 'testing.py'])
    except KeyboardInterrupt:
        break

Sie können dieses Programm in den Hintergrund stellen, und wenn Sie aufhören möchten, ziehen Sie es einfach in den Vordergrund und beenden Sie es.

Anthon
quelle
6

Sie sollten dies nicht wirklich für die Produktion verwenden, aber Sie könnten:

#!/bin/sh

while true; do
  nohup python testing.py >> test.out
done &

Wenn der Python-Prozess aus irgendeinem Grund beendet wird, wird die Shell-Schleife fortgesetzt und neu gestartet, wobei sie .outwie gewünscht an die Datei angehängt wird. Fast kein Overhead und sehr wenig Zeit zum Einrichten.

K3 --- rnc
quelle
6

Es gibt verschiedene Möglichkeiten, Prozesse unter UNIX / Linux zu überwachen und neu zu erstellen. Eines der ältesten ist ein "Respawn" -Eintrag in / etc / inittab ..., wenn Sie das alte SysV-Init-System verwenden. Eine andere Methode ist die Verwendung des Supervisor-Daemons aus dem daemontools- Paket von DJ Bernstein . Andere Optionen sind die Verwendung von Funktionen in Ubuntu upstart ... oder systemd oder anderen.

Sie können sich aber Alternativen init und insbesondere den Python-Code für Pardus: mudur daemon ansehen .

Wenn Sie sich für einen Cron-Job (und die Verarbeitung von PID-Dateien) entscheiden, sollten Sie diesen PEP 3143 lesen und möglicherweise dessen Referenzimplementierung verwenden.

Wie ich in meinen anderen Kommentaren angedeutet habe, ist die robuste Handhabung von PID-Dateien schwierig. Es ist anfällig für Rennen und Corner Cases. Es wird schwieriger, wenn die Wahrscheinlichkeit besteht, dass Ihre PID-Datei auf einem NFS oder einem anderen vernetzten Dateisystem landet (ein Teil der Atomicity garantiert, dass Sie bei einigen Versionen und Implementierungen von NFS die Semantik der Dateibehandlung auf richtigen lokalen UNIX- / Linux-Dateisystemen verlieren). beispielsweise). Auch die Semantik der Dateisperrung unter UNIX kann schwierig sein. (Wird eine flockoder fcntlSperre in Ihrem Zielbetriebssystem sofort freigegeben, wenn der Prozess, der sie hält, beispielsweise mit SIGKILL beendet wird?)

Jim Dennis
quelle
3

Sie können auch verwenden mit ps- watcher Überwachung von Monitoren oder Prozessen verwenden

Monit ist ein Open Source-Dienstprogramm zum Verwalten und Überwachen von Prozessen, Programmen, Dateien, Verzeichnissen und Dateisystemen auf einem UNIX-System. Monit führt automatische Wartungs- und Reparaturarbeiten durch und kann in Fehlersituationen sinnvolle kausale Aktionen ausführen.

Hier ist ein Beispiel für Ihr Szenario:

check process myprocessname
        matching "myprocessname"
        start program = "nohup /usr/bin/python /path/testing.py > /tmp/test.out &"
        stop program = "/usr/bin/killall myprocessname"

Schauen Sie sich einige Beispiele an

Rahul Patil
quelle
1

Sie benötigen einen Supervisor, den Sie verwenden können Supervisor verwenden . Es ist ein Python-basierter Supervisor, der bei Bedarf leicht geändert werden kann.

Die Steuerung erfolgt mit Dateien mit INI-Dateisyntax.

user41123
quelle
0

Terdons Antwort hat bei mir nicht funktioniert, weil pgrep -f testing.py es nie „versagt“ hat. Es würde die PID für den Cron-Job abrufen (wegen der Option -f). Ohne die Option -f kann pgrep testing.py jedoch nicht finden, da es keinen Prozess namens testing.py gibt.

Meine Lösung war, dies zu ändern

pgrep -f testing.py

zu

pgrep -f testing.py | pgrep python

Dies bedeutet, dass der vollständige Crontab-Auftrag wie folgt lautet:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out
Matt
quelle
0

In meinem Fall wollte ich als schnelle Lösung mein Programm am Laufen halten, wenn es mit einem Fehler beendet oder beendet wurde. Andererseits wollte ich die Ausführung stoppen, wenn das Programm korrekt beendet wurde (Rückkehrcode = 0)

Ich habe es auf Bash getestet. Es sollte in jeder anderen Shell gut funktionieren

#!/bin/sh

echo ""
echo "Use: $0 ./instagram.py"
echo ""

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done)
user9869932
quelle
0

Für die Antwort von terdon pgrep -f testing.pywird gemäß den Kommentaren hier nie false zurückgegeben :

Ich denke, das Problem ist, dass cron eine Shell erzeugt, um Ihren Befehl auszuführen, und die Argumente dieser Shell von pgrep abgeglichen werden, da Sie -f verwenden

Für Matts Antwort pgrep -f testing.pyist es nutzlos, da es pgrep pythonmit jedem laufenden Python-Skript übereinstimmt. Wenn also zwei Python-Skript-Cronjobs ausgeführt werden, wird der zweite Cronjobs niemals ausgeführt.

Und dann habe ich die Lösung pgrep -f testing.pyim Kommentar hier gefunden: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Mein Cron für das Ausführen von zwei Python-Skripten:

* * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript1\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript1.py

0 * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript2\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript2.py
Frank
quelle