web-dev-qa-db-fra.com

Comment redémarrer le script Python automatiquement s'il est tué ou meurt

J'exécute mon Python en arrière-plan sur ma machine Ubuntu (12.04) comme ceci -

Nohup python testing.py > test.out &

Maintenant, il pourrait être possible qu'à un certain stade, mon ci-dessus Python script peut mourir pour une raison quelconque.

Je pense donc avoir une sorte de cron agent dans le script shell bash qui peut redémarrer mon script ci-dessus Python automatiquement s'il est tué pour une raison quelconque.

Est-ce possible? Si oui, quelle est la meilleure façon de résoudre ce genre de problème?

MISE À JOUR:

Après avoir créé le testing.conf fichier comme celui-ci -

chdir /tekooz
exec python testing.py
respawn

J'ai couru sous la commande Sudo pour le démarrer, mais je ne vois pas ce processus se dérouler derrière en utilisant ps ax?

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

Une idée pourquoi px ax ne me montre rien? Et comment vérifier si mon programme fonctionne ou non?

Voici mon script python -

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

Sur Ubuntu (jusqu'à 14.04, 16.04 et versions ultérieures, utilisez systemd) peut utiliser upstart pour le faire, mieux qu'un travail cron. Vous mettez une configuration de configuration dans /etc/init et assurez-vous de spécifier respawn

Il peut s'agir d'un fichier minimal /etc/init/testing.conf (éditez comme root):

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

Et vous pouvez tester avec /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)

et commencez par:

Sudo start testing

et suivez ce qui se passe (dans une autre fenêtre) avec:

tail -f /var/tmp/testing.log

et arrêtez avec:

Sudo stop testing

Vous pouvez également ajouter [start on][2] pour que la commande démarre au démarrage du système.

24
Zelda

Vous pouvez également adopter une approche plus orientée Shell. Demandez à votre cron de rechercher votre script et de le relancer s'il meurt.

  1. Créez un nouveau crontab en exécutant crontab -e. Cela fera apparaître une fenêtre de votre éditeur de texte préféré.

  2. Ajoutez cette ligne au fichier qui vient de s'ouvrir

    */5 * * * * pgrep -f testing.py || Nohup python /home/you/scripts/testing.py > test.out
    
  3. Enregistrez le fichier et quittez l'éditeur.

Vous venez de créer un nouveau crontab qui sera exécuté toutes les 5 minutes et lancera votre script à moins qu'il ne soit déjà en cours d'exécution. Voir ici pour un joli petit tutoriel sur cron. Les documents officiels d'Ubuntu sur cron sont ici .

La commande en cours d'exécution est pgrep qui recherche dans les processus en cours d'exécution la chaîne donnée dans la ligne de commande. pgrep foo recherchera un programme nommé foo et renverra son identifiant de processus . pgrep -f lui fait rechercher toute la ligne de commande utilisée pour lancer le programme et pas seulement le nom du programme (utile car il s'agit d'un script python script).

Le || le symbole signifie "faites ceci si la commande précédente a échoué". Donc, si votre script n'est pas en cours d'exécution, le pgrep échouera car il ne trouvera rien et votre script sera lancé.

21
terdon

Il existe plusieurs façons de surveiller et de réapparaître les processus sous UNIX/Linux. L'une des plus anciennes est une entrée "respawn" dans/etc/inittab ... si vous utilisez l'ancien système d'initialisation SysV. Une autre méthode consiste à utiliser le démon superviseur du package - daemontools de DJ Bernstein. D'autres options consistent à utiliser les fonctionnalités d'Ubuntu upstart ... ou systemd ou autres.

Mais vous pouvez regarder alternatives init et dans le Python pour Pardus: mudur daemon en particulier.

Si vous décidez d'aller avec un travail cron (et la gestion des fichiers PID), alors envisagez de lire ceci PEP 314 et peut-être d'utiliser son implémentation de référence.

Comme je l'ai mentionné dans mes autres commentaires, la gestion robuste des fichiers PID est délicate. Il est sujet aux courses et aux cas d'angle. Cela devient plus difficile s'il y a une chance que votre fichier PID se retrouve sur un système de fichiers NFS ou un autre système de fichiers en réseau (une partie de l'atomicité garantit que vous obtenez avec la sémantique de gestion des fichiers sur une bonne locale Les systèmes de fichiers UNIX/Linux vont sur certaines versions et implémentations de NFS, par exemple). La sémantique autour du verrouillage de fichiers sous UNIX peut également être délicate. (Un verrou flock ou fcntl est-il libéré rapidement, dans votre système d'exploitation cible, lorsque le processus qui le détient est tué avec SIGKILL, par exemple?).

6
Jim Dennis

Vous pouvez demander au programme de test de rediriger la sortie à l'aide d'une option de ligne de commande, puis d'utiliser un simple script python pour redémarrer le programme indéfiniment:

import subprocess

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

vous pouvez mettre ce programme en arrière-plan, et une fois que vous voulez arrêter, tirez-le simplement au premier plan et tuez-le.

6
Anthon

Vous ne devriez pas vraiment l'utiliser pour la production, mais vous pourriez:

#!/bin/sh

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

Si, pour une raison quelconque, le processus python se termine, la boucle Shell continuera et redémarrera, en ajoutant à .out fichier comme vous le souhaitez. Presque pas de frais généraux et prend très peu de temps à installer.

6
K3---rnc

Vous pouvez également utiliser monit Ou Surveillance de processus avec ps-watcher

Monit est un utilitaire open source de gestion et de surveillance des processus, programmes, fichiers, répertoires et systèmes de fichiers sur un système UNIX. Monit effectue des opérations de maintenance et de réparation automatiques et peut exécuter des actions causales significatives dans des situations d'erreur.

Voici un exemple pour votre scénario:

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

Jetez un œil aux exemples de monit

3
Rahul Patil

Vous avez besoin d'un superviseur, vous pouvez utiliser superviseur . Il s'agit d'un superviseur basé sur python, donc facile à modifier si nécessaire).

Le contrôle se fait avec des fichiers avec une syntaxe de fichier .ini.

1
user41123

Dans mon cas, en tant que solution rapide, je voulais garder mon programme en cours d'exécution lorsqu'il s'est terminé avec une erreur ou s'il a été tué. D'un autre côté, je voulais arrêter l'exécution lorsque le programme s'est terminé correctement (code retour = 0)

Je l'ai testé sur Bash. Cela devrait fonctionner correctement dans n'importe quel autre Shell

#!/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)
0
user9869932

Pour la réponse de terdon, pgrep -f testing.py ne retournera jamais faux selon les commentaires dans ici :

Je pense que le problème est que cron génère un Shell pour exécuter votre commande, et les arguments de ce Shell sont mis en correspondance par pgrep puisque vous utilisez -f

Pour la réponse de Matt, pgrep -f testing.py est inutile puisque pgrep python correspond à n'importe quel script Python. Donc, si deux cronjob de script Python), le second cronjob ne s'exécutera jamais.

Et puis j'ai trouvé la solution pour résoudre pgrep -f testing.py dans le commentaire ici: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Mon cron pour l'exécution de deux scripts Python:

* * * * * 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
0
Frank

La réponse de Terdon, n'a pas fonctionné pour moi, parce que pgrep -f testing.py n'a jamais "échoué". Il saisirait le pid pour le travail cron (en raison de l'option -f). Cependant, sans l'option -f, pgrep ne trouvera pas testing.py car il n'y a pas de processus appelé testing.py.

Ma solution était de changer

pgrep -f testing.py

à

pgrep -f testing.py | pgrep python

cela signifie que le travail complet de crontab serait:

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