2012-07-20 11 views
8

Estoy escribiendo una aplicación web de Python usando Flask. Mi aplicación establece una conexión con otro servidor al inicio y se comunica con ese servidor periódicamente en segundo plano.Flask/Werkzeug depurador, modelo de proceso y código de inicialización

Si no utilizo el depurador interno de Flask (invocando app.run con debug = False), no hay problema.

Si utilizo el depurador integrado (invocando app.run con debug = True), Flask inicia un segundo proceso de Python con el mismo código. Es el proceso secundario que termina escuchando conexiones HTTP y generalmente comportándose como se supone que debe hacerlo mi aplicación, y supongo que el padre está ahí para vigilarlo cuando el depurador se active.

Sin embargo, esto causa estragos en mi código de inicio, que se ejecuta en ambos procesos; Termino con 2 conexiones al servidor externo, 2 procesos que inician sesión en el mismo archivo de registro y, en general, se cruzan uno sobre el otro.

Supongo que no debería estar haciendo un trabajo real antes de la llamada a app.run(), pero ¿dónde debería poner este código de inicialización (que solo quiero ejecutar una vez por grupo de proceso de Flask, independientemente del modo de depuración , pero que necesita ejecutarse al inicio e independientemente de las solicitudes del cliente)?

Encontré this question about "Flask auto-reload and long-running thread" que es algo relacionado, pero algo diferente, y la respuesta no me ayudó. (Yo también tengo un hilo de larga duración separado marcado como un hilo de daemon, pero se cancela cuando se activa el reloader, pero el problema que estoy tratando de resolver es antes de que tenga que volver a cargarse. No me preocupa el volver a cargar; me preocupa el proceso adicional y la forma correcta de evitar la ejecución de código innecesario en el proceso principal.)

+0

Gracias por esta pregunta (y respuesta), esta me dejó perplejo al intentar algo similar. – akatkinson

Respuesta

9

Confirmé que este comportamiento se debe a Werkzeug, no al Frasco propiamente dicho, y está relacionado con el recargador . Puede ver esto en serve.py de Werkzeug - en run_simple(), si use_reloader es verdadero, invoca make_server a través de una función auxiliar run_with_reloader()/restart_with_reloader() que hace un subprocess.call (sys.executable), después de configurar un variable de entorno WERKZEUG_RUN_MAIN en el entorno que heredará el subproceso.

trabajé alrededor de ella con un corte bastante feo: en mi función principal, antes de crear el objeto de aplicación WSGI y llamando app.run(), debo buscar WERKZEUG_RUN_MAIN:

if use_reloader and not os.environ.get('WERKZEUG_RUN_MAIN'): 
    logger.warning('startup: pid %d is the werkzeug reloader' % os.getpid()) 
else: 
    logger.warning('startup: pid %d is the active werkzeug' % os.getpid() 
    # my real init code is invoked from here 

Tengo la sensación de este sería mejor hacerlo desde dentro del objeto de la aplicación, si hay un método que se llama antes de que Werkzeug comience a servirlo. Sin embargo, no conozco ese método.

Todo esto se reduce a: en run_simple.py de Werkzeug, solo va a haber una llamada eventual a make_server(). Serve_forever(), pero puede haber dos llamadas a run_simple() (y la pila de llamadas completa arriba hasta ese punto) antes de llegar a make_server().

+0

Creo que esta respuesta podría estar desactualizada. Flask ahora tiene un decorador ['before_first_request'] (http://flask.pocoo.org/docs/0.10/api/#flask.Flask.before_first_request). –

Cuestiones relacionadas