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

31

J'exécute mon script 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 dessus Python scriptpuisse mourir pour une raison quelconque.

Je pense donc avoir une sorte de cron agentscript shell bash qui peut redémarrer mon script Python ci-dessus 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.conffichier comme ceci -

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 s'exécuter 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?

Ceci est mon script python -

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

Réponses:

24

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

Il peut s'agir d'un fichier minimal /etc/init/testing.conf(modifier en tant que 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.

Zelda
la source
Si vous utilisez un travail cron, vous souhaiterez implémenter ou trouver du code pour une gestion robuste des fichiers PID. Vous voulez que votre service / script / démon crée un fichier PID (généralement situé sous / var / run) et que son code de démarrage vérifie si le contenu du fichier est périmé (laissé par un processus interrompu). Ce type de code est étonnamment difficile à écrire sans course ni casse. stackoverflow.com/questions/788411/…
Jim Dennis
@Zelda: Merci pour la suggestion .. Je suis nouveau dans le monde Linux / Unix .. Quel type de changements je suis censé apporter au /etc/initfichier? Si vous pouvez me fournir un guide étape par étape, alors je serai en mesure d'apprendre quelque chose et de faire la bonne chose ..
arsenal
@Webby J'ai rendu la réponse plus complète. Si vous ne voulez pas ouvrir un fichier pour la sortie et réécrire vos instructions d'impression, vous pouvez faire quelque chose comme sys.stdout = open(file_name, 'w')au début.
Zelda
Merci Zelda. J'ai apprécié votre aide .. J'ai mis à jour la question avec quelques détails .. J'essaie de faire comme ça pour voir si mon testing.py fonctionne ou non .. Il ne me montre pas s'il fonctionne ou non .. px ax | grep testing.py.. Ça ne me rend rien? Une idée pourquoi?
arsenal
Vous devez mettre le tout dans une clause try / except et écrire dans un fichier journal quelle exception a été générée et que le programme se ferme. Peut-être que l'instruction print ne fonctionne pas car elle ne peut pas écrire sur stdout.
Zelda
20

Vous pouvez également adopter une approche plus orientée shell. Cherchez votre cronscript et relancez-le 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 d'en créer un nouveau crontabqui s'exécutera 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 cronsont ici .

La commande en cours d'exécution est celle pgrepqui recherche dans les processus en cours d'exécution la chaîne donnée dans la ligne de commande. pgrep foorecherchera un programme nommé fooet renverra son identifiant de processus . pgrep -fle 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).

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é.

terdon
la source
Merci .. Mais je suis nouveau sur linux et unix alors je ne sais pas où est crontab? S'agit-il d'un fichier dans ma machine Ubuntu quelque part?
arsenal
@Webby voir la réponse mise à jour.
terdon
Merci terdon .. Je peux exécuter cette commande crontab -edepuis le répertoire où se trouve mon script python .. Correct?
arsenal
1
@Webby, vous pouvez l'exécuter où vous le souhaitez. cronest un démon de planification, c'est un service qui s'exécute en arrière-plan. Si votre script python n'est pas dans votre $PATH(si vous ne pouvez pas le lancer de n'importe où mais devez être dans son répertoire) utilisez le chemin complet du script comme dans ma réponse mise à jour.
terdon
Merci. Maintenant, cela a du sens .. Je viens de créer un nouveau crontab et édité le fichier en ajoutant la même ligne unique, mais pendant 1 minute .. J'ai déjà créé un script Hello World Python tournant alors que True est nommé testing.py .. Après l'enregistrement le fichier crontab, il devrait démarrer automatiquement testing.py après 1 minute? Et puis continuez à vérifier toutes les 1 minute si le script python est en cours d'exécution ou non? Si oui, après avoir enregistré le fichier crontab -e, j'ai fait ps ax | grep testing.py et je ne vois aucun processus pour cela?
arsenal le
6

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.

Anthon
la source
6

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 du shell continuera et redémarrera, en ajoutant le .outfichier comme vous le souhaitez. Presque pas de frais généraux et prend très peu de temps à installer.

K3 --- rnc
la source
6

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 les alternatives init et dans le code Python pour Pardus: démon mudur en particulier.

Si vous décidez d'aller avec un travail cron (et la gestion des fichiers PID), alors envisagez de lire ce PEP 3143 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. Il 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 de fichiers sur les systèmes de fichiers UNIX / Linux locaux appropriés disparaissent 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 flockou fcntlest-il libéré rapidement, dans votre système d'exploitation cible, lorsque le processus le tenant est tué avec SIGKILL, par exemple?).

Jim Dennis
la source
3

Vous pouvez également utiliser la surveillance Monit Or Process avec ps-watcher

Monit est un utilitaire open source pour la gestion et la 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

Rahul Patil
la source
1

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

Le contrôle est avec des fichiers avec la syntaxe de fichier .ini.

user41123
la source
0

La réponse de Terdon n'a pas fonctionné pour moi, car elle pgrep -f testing.pyn'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
Mat
la source
0

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. Il devrait fonctionner correctement dans tout 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)
user9869932
la source
0

Pour la réponse de terdon, pgrep -f testing.pyne retournera jamais faux selon les commentaires 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.pyest inutile car pgrep pythoncorrespond à tout script Python en cours d'exécution. Donc, si deux cronjob de script Python, le second cronjob ne s'exécutera jamais.

Et puis j'ai trouvé la solution à résoudre pgrep -f testing.pydans le commentaire ici: /ubuntu/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
Franc
la source