2011-12-31 11 views
25

Recientemente he comenzado a experimentar con el uso de Python para el desarrollo web. Hasta ahora he tenido éxito usando Apache con mod_wsgi y el framework web de Django para Python 2.7. Sin embargo, me he encontrado con algunos problemas con la ejecución constante de procesos, la actualización de la información y demás.¿Cómo puedo ejecutar procesos de Python a largo plazo (infinitos)?

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

  • De vez en cuando uno de los procesos se acaba de dejar de fumar. Reviso ps por la mañana y el proceso simplemente se va. No se registraron errores (estoy usando el módulo logging), y estoy cubriendo todas las excepciones que pueda pensar y registrándolas. Además, no creo que estos procesos de abandono tengan algo que ver con mi código, porque todos mis procesos ejecutan un código completamente diferente y salen en intervalos bastante similares. Podría estar equivocado, por supuesto. ¿Es normal que los procesos de Python simplemente mueran después de que se han ejecutado durante días/semanas? ¿Cómo debería abordar este problema? ¿Debo escribir otro daemon que compruebe periódicamente si los otros daemons aún se están ejecutando? ¿Qué pasa si ese daemon se detiene? No sé cómo manejar esto.

  • ¿Cómo puedo saber mediante programación si un proceso todavía se está ejecutando o no? Estoy guardando los archivos PID en /var/run y comprobando 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 se mantendrá. Por lo tanto, tengo que eliminar estos archivos cada vez que un proceso falla (un par de veces por semana), lo que de alguna manera frustra el propósito. Supongo que podría verificar si un proceso se está ejecutando en el PID en el archivo, pero ¿qué ocurre si otro proceso ha comenzado y se le asignó el PID del proceso inactivo? Mi daemon pensaría que el proceso está funcionando bien, incluso si hace tiempo que murió. Una vez más, estoy perdido cómo lidiar con esto.

Cualquier respuesta útil sobre cómo mejores procesos infinita Python de ejecución, con suerte también arrojar alguna luz sobre los problemas anteriores, aceptaré


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

+0

Si agrega algunos ejemplos de código que muestran el código de los daemons que se bloquean, es posible que podamos abordar aspectos específicos. Lo primero es lo primero, eliminaría todo el código de tus scripts que tratan sobre bifurcación, supervisión, redirección, etc. –

+0

Puedes aclarar si estás bifurcando estos procesos de daemon desde la aplicación WSGI que se ejecuta bajo mod_wsgi o por separado. No debería realizar dicha creación de proceso desde una aplicación que se ejecuta en mod_wsgi. –

+0

Parece que hay mucha publicidad aquí. Quiero decir, esta es una pregunta bien colocada, en la que se da una respuesta a una tecnología específica, a la que se da otra respuesta en la que se responde de nuevo "También terminé usando" otra tecnología más (¿competitiva?) ... – citn

Respuesta

24

Abriré afirmando que esto es one manera de gestionar un proceso de larga ejecución (LRP) - no de facto por ningún tramo.

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

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

El uso de un sistema como supervisord, usted básicamente escribir un script en Python convencional que realiza una tarea, mientras que 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 la secuencia de comandos de esta manera hace que sea sencillo y conveniente para desarrollar y depurar (se puede comenzar fácilmente/parada en un terminal, viendo la salida del registro como se desarrollan los acontecimientos). Cuando llega el momento de lanzar a producción, simplemente define una configuración de supervisor que llama a su script (aquí está el completo ejemplo para definir un "programa", muchos de los cuales son opcionales: http://supervisord.org/configuration.html#program-x-section-example).

supervisor tiene un montón de opciones de configuración, así que no enumerarlos, pero he de decir que resuelve de forma específica los problemas que usted describe:

  • a segundo plano/Daemonizing
  • PID seguimiento (puede se configurará para reiniciar un proceso si termina inesperadamente)
  • Registre normalmente en su secuencia de comandos (controlador de flujo si utiliza el módulo de registro en lugar de imprimir) pero deje que el supervisor lo redireccione a un archivo por usted.
+0

Terminé volcando mi propia solución daemonize, ya que resulta que no tengo suficiente experiencia en el tema. También terminé usando [forever by nodejitsu] (https://github.com/nodejitsu/forever) que es una deliciosa aplicación no-config-required (pero miles de configuraciones posibles) donde solo necesitas especificar ejecutables y argumentos. y la secuencia de comandos se ejecutará como un daemon para siempre, reiniciando al estrellarse. También resolví algunos errores de larga ejecución comprobando los registros de salida automáticos. Estoy aceptando su respuesta como la más cercana a mi solución – Hubro

+0

¿El Supervisor reiniciará su secuencia de comandos después de salir manualmente de su secuencia de comandos? –

+1

@Jakobud cuando el supervisor está gestionando un proceso que sale (a través de 'sys.exit()', una excepción no detectada, o si la secuencia de comandos llega a su fin - tal vez no haya un bucle?), Intentará reiniciarlo. Hay configuraciones para controlar la cantidad de intentos de reinicio que se deben realizar y cuánto tiempo esperar entre intentos. Una vez que se hayan gastado todos los intentos, se dará por vencido. Si desea detener un trabajo en ejecución, debe usar supervisorctl para apagarlo. –

2

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

En primer lugar, si tus demonios fallan, deberías solucionarlo. Solo los programas con errores deberían fallar. Tal vez debería lanzarlos bajo un depurador y ver qué sucede cuando fallan (si es posible). ¿Tiene algún registro de rastreo en estos procesos? Si no, agrégalos. Eso podría ayudar a diagnosticar su falla.

En segundo lugar, ¿están sus demonios prestando servicios (abriendo pipas y esperando solicitudes) o están realizando una limpieza periódica? Si son procesos de limpieza periódica, debe usar cron para iniciarlos periódicamente en lugar de hacer que se ejecuten en un ciclo infinito. Los procesos de cron deben preferirse a los procesos de daemon. Del mismo modo, si se trata de servicios que abren puertos y solicitudes de servicio, ¿ha considerado hacer que funcionen con INETD? De nuevo, un único daemon (inetd) debería preferirse a un grupo de procesos daemon.

En tercer lugar, guardar un PID en un archivo no es muy efectivo, como habrás descubierto. Tal vez un IPC compartido, como un semáforo, funcionaría mejor. Sin embargo, no tengo ningún detalle aquí.

En cuarto lugar, a veces necesito cosas para ejecutar en el contexto del sitio web. Utilizo un proceso cron que llama a wget con una URL de mantenimiento. Establece una cookie especial e incluye la información de la cookie con la línea de comando de wget. Si la cookie especial no existe, devuelva 403 en lugar de realizar el proceso de mantenimiento. El otro beneficio aquí es iniciar sesión en la base de datos y otras preocupaciones ambientales evitadas, ya que el código que sirve páginas web normales está sirviendo el proceso de mantenimiento.

Espero que te dé ideas. Creo que evitar demonios si puedes es el mejor lugar para comenzar. Si puedes ejecutar tu python dentro de mod_wsgi, eso te ahorra tener que soportar múltiples "entornos". La depuración de un proceso que falla después de ejecutar durante días a la vez es simplemente brutal.

+1

Gracias por los buenos consejos. Especifico que estoy ejecutando Ubuntu por cierto :) – Hubro

+0

Oh, al final. No lo vi – jmucchiello

2

Considere los procesos de Python como capaces de ejecutarse "para siempre" suponiendo que no haya pérdidas 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 fugas de memoria, es posible que pueda ejecutar 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 que han sobrevivido muy bien durante casi dos años con hardware limitado, antes de que se necesitara mover el hardware.)

programas Asegurar reinician cuando mueren solían ser muy simple de vuelta cuando las distribuciones de Linux utilizan SysV-style init - que acaba de añadir una nueva línea a la /etc/inittab y init(8) frezaría su programa en el arranque y volver a desovar si que muera. (No conozco ningún mecanismo para replicar esta funcionalidad con el nuevo upstart init -replacement que muchas distribuciones están usando actualmente. No digo que sea imposible, simplemente no sé cómo hacerlo.)

Pero incluso el mecanismo init(8) de años pasados ​​no era tan flexible como a algunos les hubiera gustado. El paquete daemontools de DJB es un ejemplo de las herramientas de control y supervisión de procesos destinadas a mantener a los daemons para siempre. El paquete Linux-HA proporciona otra herramienta similar, aunque podría proporcionar demasiada funcionalidad "adicional" para estar justificada para esta tarea. monit es otra opción.

Cuestiones relacionadas