¿Cómo puedo ejecutar procesos Python a largo plazo (infinitos)?


Recientemente he comenzado a experimentar con el uso de Python para el desarrollo web. Hasta ahora he tenido cierto éxito usando Apache con mod_wsgi y el marco web Django para Python 2.7. Sin embargo, me he encontrado con algunos problemas con los procesos que se ejecutan constantemente, la actualización de la información y tal.

He escrito un guión que llamo "daemonManager.py" eso puede iniciar y detener todos o cada uno de los bucles de actualización de Python (¿debería llamarlos Demonios?). Lo hace bifurcando, luego cargando el módulo para las funciones específicas se debe ejecutar e iniciar un bucle infinito. Guarda un archivo PID en /var/run para realizar un seguimiento del proceso. Hasta ahora todo bien. Los problemas que he encontrado son:

  • De vez en cuando uno de los procesos acaba de salir. Compruebo ps por la mañana y el proceso acaba de desaparecer. No se registraron errores (estoy usando el módulo logging), y estoy cubriendo todas las excepciones que se me ocurren y registrándolas. Además, no creo que estos procesos de dejar de fumar tengan nada que ver con mi código, porque todos mis procesos ejecutan código completamente diferente y salen a intervalos bastante similares. Podría estar equivocado, por supuesto. ¿Es normal que los procesos de Python mueran después de que se hayan ejecutado durante días/semanas? ¿Cómo debo abordar este problema? ¿Debo escribir otro demonio que verifique periódicamente si los otros demonios todavía están en ejecución? ¿Y si ese demonio se detiene? No sé cómo manejar esto.

  • ¿Cómo puedo saber programáticamente si un proceso todavía se está ejecutando o no? Soy guardar los archivos PID en /var/run y comprobar si el archivo PID está allí para determinar si el proceso se está ejecutando o no. Pero si el proceso simplemente muere por causas inesperadas, el archivo PID permanecerá. Por lo tanto, tengo que eliminar estos archivos cada vez que un proceso se bloquea (un par de veces por semana), que tipo de derrota el propósito. Supongo que podría comprobar si un proceso se está ejecutando en el PID en el archivo, pero ¿qué pasa si otro proceso ha comenzado y se le asignó el PID del proceso muerto? Mi demonio pensaría que el proceso está funcionando bien incluso si está muerto hace mucho tiempo. Una vez más estoy en una pérdida de cómo lidiar con esto.

Cualquier respuesta útil sobre cómo mejor ejecutar infinitos procesos de Python, con suerte también arrojando algo de luz sobre los problemas anteriores, aceptaré


Estoy usando Apache 2.2.14 en una máquina Ubuntu.
Mi versión de Python es 2.7.2

Author: Hubro, 2011-12-31

3 answers

Abriré diciendo que esta es una forma de administrar un proceso de larga ejecución (LRP) not no de facto por ningún tramo.

En mi experiencia, el mejor producto posible proviene de concentrarse en el problema específico con el que está tratando, mientras delega la tecnología de soporte a otras bibliotecas. En este caso, me refiero al acto de los procesos de backgrounding (el arte de la bifurcación doble), monitoreo y redirección de registros.

Mi solución favorita es http://supervisord.org /

Usando un sistema como supervisord, básicamente escribes un script python convencional que realiza una tarea mientras está atascado en un bucle "infinito".

#!/usr/bin/python

import sys
import time

def main_loop():
    while 1:
        # do your stuff...
        time.sleep(0.1)

if __name__ == '__main__':
    try:
        main_loop()
    except KeyboardInterrupt:
        print >> sys.stderr, '\nExiting by user request.\n'
        sys.exit(0)

Escribir su script de esta manera hace que sea simple y conveniente desarrollar y depurar (puede iniciarlo/detenerlo fácilmente en un terminal, observando la salida del registro a medida que se desarrollan los eventos). Cuando llega el momento de lanzarlo a producción, simplemente define una configuración de supervisor que llame a tu script (aquí está la completo ejemplo para definir un "programa", gran parte del cual es opcional: http://supervisord.org/configuration.html#program-x-section-example).

Supervisor tiene un montón de opciones de configuración, así que no las enumeraré, pero diré que resuelve específicamente los problemas que describe:

  • Backgrounding/Daemonizing
  • Seguimiento PID (se puede configurar para reiniciar un proceso si termina inesperadamente)
  • Iniciar sesión normalmente su script (controlador de flujo si usa el módulo de registro en lugar de imprimir), pero deje que supervisor redirija a un archivo por usted.
 24
Author: Owen Nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-31 02:14:21

Asumo que está ejecutando Unix/Linux, pero realmente no lo dice. No tengo ningún consejo directo sobre su asunto. Así que no espero ser la respuesta "correcta" a esta pregunta. Pero hay algo que explorar aquí.

Primero, si tus demonios están fallando, deberías arreglarlo. Solo los programas con errores deberían fallar. Tal vez debería lanzarlos bajo un depurador y ver qué sucede cuando se bloquean (si eso es posible). ¿Tiene algún registro de seguimiento en estos procesos? Si no, agrégalas. Que podría ayudar a diagnosticar su accidente.

En segundo lugar, ¿están sus demonios proporcionando servicios (abriendo tuberías y esperando solicitudes) o están realizando una limpieza periódica? Si son procesos de limpieza periódicos, debe usar cron para iniciarlos periódicamente en lugar de ejecutarlos en un bucle infinito. Los procesos Cron deben preferirse a los procesos daemon. Del mismo modo, si son servicios que abren puertos y solicitudes de servicio, ¿ha considerado hacerlos funcionar con INETD? Una vez más, un solo daemon (inetd) debe ser preferido a un grupo de procesos daemon.

Tercero, guardar un PID en un archivo no es muy efectivo, como has descubierto. Tal vez una IPC compartida, como un semáforo, funcionaría mejor. No tengo ningún detalle aquí.

En cuarto lugar, a veces necesito que las cosas se ejecuten en el contexto del sitio web. Uso un proceso cron que llama a wget con una URL de mantenimiento. Configura una cookie especial e incluye la información de la cookie en la línea de comandos de wget. Si la cookie especial no existe, devolver 403 en lugar de realizar el proceso de mantenimiento. El otro beneficio aquí es el inicio de sesión en la base de datos y otras preocupaciones ambientales de evitar ya que el código que sirve páginas web normales están sirviendo al proceso de mantenimiento.

Espero que eso te dé ideas. Creo que evitar demonios si puedes es el mejor lugar para empezar. Si puedes ejecutar tu python dentro de mod_wsgi eso te ahorra tener que soportar múltiples "entornos". Depuración de un proceso que falla después de ejecutarse durante los días a la vez son brutales.

 2
Author: jmucchiello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-31 02:04:29

Debe considerar que los procesos de Python pueden ejecutarse "para siempre" asumiendo que no tiene ninguna fuga de memoria en su programa, el intérprete de Python o cualquiera de las bibliotecas / módulos de Python que está utilizando. (Incluso frente a las fugas de memoria, es posible que pueda ejecutarse para siempre si tiene suficiente espacio de intercambio en una máquina de 64 bits. Décadas, si no siglos, deberían ser factibles. He tenido procesos de Python sobrevivir muy bien durante casi dos años en hardware limitado before antes de que el hardware necesario para ser movido.)

Asegurar que los programas se reinicien cuando mueren solía ser muy simple cuando las distribuciones de Linux usaban estilo SysVinit -- simplemente agrega una nueva línea a /etc/inittab y init(8) generará tu programa al arrancar y lo volverá a generar si muere. (No conozco ningún mecanismo para replicar esta funcionalidad con el nuevo upstart init-reemplazo que muchas distribuciones están utilizando en estos días. No estoy diciendo que sea imposible, simplemente no sé cómo hacerlo.)

Pero, incluso el mecanismo init(8) de los años pasados no era tan flexible como algunos hubieran querido. El paquete daemontools de DJB es un ejemplo de herramientas de control y monitoreo de procesos destinadas a mantener a los demonios viviendo para siempre. La suite Linux-HA proporciona otra herramienta similar, aunque podría proporcionar demasiada funcionalidad "extra" para ser justificada para esta tarea. monit es otra opción.

 2
Author: sarnold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-31 02:08:38