Cómo reiniciar el script de Python automáticamente si se mata o muere

31

Estoy ejecutando mi script Python en segundo plano en mi máquina Ubuntu (12.04) así:

nohup python testing.py > test.out &

Ahora, podría ser posible que en algún momento mi anterior Python scriptpueda morir por cualquier razón.

Así que estoy pensando en tener algún tipo de cron agentscript de shell bash que pueda reiniciar mi script Python anterior automáticamente si se elimina por cualquier razón.

¿Es posible hacerlo? En caso afirmativo, ¿cuál es la mejor manera de resolver este tipo de problema?

ACTUALIZAR:

Después de crear el testing.confarchivo así:

chdir /tekooz
exec python testing.py
respawn

Ejecuté debajo del comando sudo para iniciarlo, pero no puedo ver ese proceso ejecutándose con 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

¿Alguna idea de por qué px axe no me muestra nada? ¿Y cómo verifico si mi programa se está ejecutando o no?

Este es mi script de Python:

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

Respuestas:

24

En Ubuntu (hasta 14.04, 16.04 y posterior use systemd) puede usar upstart para hacerlo, mejor que un trabajo cron. Pones una configuración de configuración /etc/inity te aseguras de especificar respawn

Podría ser un archivo mínimo /etc/init/testing.conf(editar como root):

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

Y puedes probar con /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)

y comienza con:

sudo start testing

y sigue lo que sucede (en otra ventana) con:

tail -f /var/tmp/testing.log

y para con:

sudo stop testing

También puede agregar [start on][2]para que el comando se inicie al iniciar el sistema.

Zelda
fuente
Si usa un trabajo cron, entonces querrá implementar o encontrar algún código para el manejo robusto de archivos PID. Desea que su servicio / script / daemon cree un archivo PID (ubicado convencionalmente en / var / run) y que su código de inicio verifique si el contenido del archivo está obsoleto (dejado por un proceso finalizado). Este tipo de código es sorprendentemente difícil de escribir libre de razas y casos de esquina. stackoverflow.com/questions/788411/…
Jim Dennis
@Zelda: Gracias por su sugerencia ... Soy nuevo en el mundo Linux / Unix ... ¿Qué tipo de cambios se supone que debo hacer en el /etc/initarchivo? Si me puede proporcionar una guía paso a paso, entonces podré aprender algo y hacer lo correcto ..
arsenal
@Webby hice la respuesta más completa. Si no desea abrir un archivo para la salida y reescribir sus declaraciones de impresión, puede hacer algo como sys.stdout = open(file_name, 'w')al principio.
Zelda
Gracias Zelda Agradezco su ayuda ... Actualicé la pregunta con algunos detalles ... Estoy tratando de hacer esto para ver si mi testing.py se está ejecutando o no ... No me muestra si se está ejecutando o no px ax | grep testing.py... ¿Me está devolviendo nada? ¿Alguna idea de por qué?
arsenal el
Debe poner todo en una cláusula try / except y escribir en un archivo de registro qué excepción se generó y si el programa se cierra. Tal vez la declaración de impresión no funciona ya que no puede escribir en stdout.
Zelda
20

También podría adoptar un enfoque más orientado a la shell. Eche un cronvistazo a su script y reinícielo si muere.

  1. Cree un nuevo crontab ejecutando crontab -e. Esto abrirá una ventana de su editor de texto favorito.

  2. Agregue esta línea al archivo que acaba de abrir

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Guarde el archivo y salga del editor.

Acaba de crear una nueva crontabque se ejecutará cada 5 minutos y ejecutará su script a menos que ya se esté ejecutando. Vea aquí para ver un pequeño tutorial sobre cron. Los documentos oficiales de Ubuntu cronestán aquí .

El comando real que se ejecuta es el pgrepque busca en los procesos en ejecución la cadena dada en la línea de comando. pgrep foobuscará un programa llamado fooy devolverá su identificador de proceso . pgrep -fhace que busque en toda la línea de comando utilizada para iniciar el programa y no solo en el nombre del programa (útil porque se trata de un script de Python).

El ||símbolo significa "hacer esto si falla el comando anterior". Entonces, si su script no se está ejecutando, pgrepfallará ya que no encontrará nada y se iniciará su script.

terdon
fuente
Gracias ... Pero soy nuevo en Linux y Unix, así que no sé dónde está crontab. ¿Es este un archivo en mi máquina ubuntu en alguna parte?
arsenal
@Webby ver respuesta actualizada.
terdon
Gracias terdon. Puedo ejecutar este comando crontab -edesde el directorio donde está mi script de Python. ¿Correcto?
arsenal el
1
@Webby puedes ejecutarlo desde donde quieras. crones un demonio de programación, es un servicio que se ejecuta en segundo plano. Si su script de Python no está en su $PATH(si no puede iniciarlo desde cualquier lugar pero necesita estar en su directorio) use la ruta completa al script como en mi respuesta actualizada.
terdon
Gracias. Ahora tiene sentido ... Acabo de crear un nuevo crontab y edité el archivo agregando la misma línea, pero durante 1 minuto ... Ya he creado un script de Hello World Python que gira mientras que True se llama como testing.py ... Después de guardar el archivo crontab, debería iniciar automáticamente el testing.py después de 1 minuto? ¿Y luego sigue comprobando cada 1 minuto si el script de Python se ejecuta o no? En caso afirmativo, después de guardar el archivo crontab -e, hice ps ax | grep testing.py y no puedo ver ningún proceso para eso?
arsenal el
6

Puede hacer que el programa de prueba redirija la salida utilizando una opción de línea de comandos y luego use un script simple de Python para reiniciar el programa indefinidamente:

import subprocess

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

puedes poner este programa en segundo plano, y una vez que quieras detenerlo, simplemente llévalo al primer plano y mátalo.

Anthon
fuente
6

Realmente no deberías usar esto para la producción, pero podrías:

#!/bin/sh

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

Si, por algún motivo, el proceso de Python se cierra, el ciclo de shell continuará y lo reiniciará, agregando al .outarchivo lo que desee. Casi sin gastos generales y lleva muy poco tiempo configurarlo.

K3 --- rnc
fuente
6

Hay varias formas de monitorear y reaparecer procesos bajo UNIX / Linux. Una de las más antiguas es una entrada de "reaparición" en / etc / inittab ... si está utilizando el antiguo sistema de inicio SysV. Otro método es utilizar el demonio supervisor del paquete daemontools de DJ Bernstein . Otras opciones son usar funciones en Ubuntu upstart ... o systemd u otros.

Pero puede ver las alternativas init y en el código Python para Pardus: mudur daemon en particular.

Si decide ir con un trabajo cron (y el manejo de archivos PID), considere leer este PEP 3143 y quizás usar su implementación de referencia.

Como mencioné en mis otros comentarios, el manejo robusto de archivos PID es complicado. Es propenso a las carreras y los casos de esquina. Se vuelve más complicado si hay alguna posibilidad de que su archivo PID termine en un NFS u otro sistema de archivos en red (algunas de las atomicidades le garantizan que la semántica de manejo de archivos en sistemas de archivos UNIX / Linux locales correctos desaparece en algunas versiones e implementaciones de NFS, por ejemplo). También la semántica en torno al bloqueo de archivos bajo UNIX puede ser complicada. (¿Se libera rápidamente un bloqueo flocko fcntl, en su sistema operativo de destino, cuando el proceso que lo mantiene se elimina con SIGKILL, por ejemplo?).

Jim Dennis
fuente
3

También puede usar el monitoreo de Monit o Process con ps-watcher

Monit es una utilidad de código abierto para administrar y monitorear, procesos, programas, archivos, directorios y sistemas de archivos en un sistema UNIX. Monit realiza mantenimiento y reparación automáticos y puede ejecutar acciones causales significativas en situaciones de error.

Aquí hay un ejemplo para su escenario:

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

Echa un vistazo a los ejemplos de monit

Rahul Patil
fuente
1

Necesita un supervisor, puede usar el supervisor . Es un supervisor basado en Python, por lo tanto, es fácil de modificar si es necesario.

El control es con archivos con sintaxis de archivo .ini.

usuario41123
fuente
0

La respuesta de Terdon, no funcionó para mí, porque pgrep -f testing.pynunca estaba "fallando". Tomaría el pid para el trabajo cron (debido a la opción -f). Sin embargo, sin la opción -f, pgrep no encontrará testing.py porque no hay un proceso llamado testing.py.

Mi solución a esto fue cambiar

pgrep -f testing.py

a

pgrep -f testing.py | pgrep python

esto significa que el trabajo completo de crontab sería:

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

En mi caso, como una solución rápida, quería mantener mi programa ejecutándose cuando salió con un error o fue eliminado. Por otro lado, quería detener la ejecución cuando el programa terminaba correctamente (código de retorno = 0)

Lo he probado en Bash. Debería funcionar bien en cualquier otro caparazón

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

Para la respuesta de terdon, pgrep -f testing.pynunca volverá falso de acuerdo con los comentarios aquí :

Creo que el problema es que cron genera un shell para ejecutar su comando, y los argumentos de ese shell coinciden con pgrep ya que está utilizando -f

Para la respuesta de Matt, pgrep -f testing.pyes inútil ya que pgrep pythoncoincide con cualquier script Python en ejecución. Entonces, si dos cronjob de script Python, el segundo cronjob nunca se ejecutará.

Y luego encontré la solución para resolver pgrep -f testing.pyen el comentario aquí: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Mi cron para ejecutar dos scripts de 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
Franco
fuente