El uso del multiprocesamiento de python hace que la respuesta se cuelgue de gunicorn

Primero, admitiré que hay unas pocas o muchas palabras clave en ese título, pero realmente estoy tratando de capturar el problema de la manera correcta. El problema aquí es que parece que no puedo crear correctamente un subproceso utilizando el módulo de multiprocesamiento de python sin que esto provoque que se cuelgue la respuesta de la página web. He probado algunas versiones recientes de Gunicorn y el problema persiste. Curiosamente, el problema nunca fue un problema en el servidor de Ubuntu, pero ahora, al mover la aplicación a rhel6.5, este problema se ha presentado. Aquí está el flujo de trabajo:

-ruta se golpea -se envía un formulario que golpea la ruta y activa un proceso de multiprocesamiento. () (Proceso) que se creará, donde el trabajo realizado se suspenderá durante 30 segundos -la ruta parece terminar, como una statement de impresión después de la llamada de multiprocesamiento impreso, sin embargo, el navegador mantiene la conexión abierta y no ‘termina de cargarse’ (muestra la página) hasta que finalizan los 30 segundos de reposo

Tenga en cuenta que el envío del formulario no es parte de este problema, solo ayuda a ver cómo ocurre el problema.

Aquí hay una ruta y función muy simple que produce el problema:

def multi(): print 'begin multi' time.sleep(30) print 'end multi' @app.route('/multiprocesstest', methods=['GET','POST']) def multiprocesstest(): syntaxForm = forms.mainSyntaxForm() if syntaxForm.validate_on_submit(): print 'before multi call' th = multiprocessing.Process(target=multi) th.start() print 'after multi call' return redirect('multiprocesstest') return render_template('syntax_main.html', form=syntaxForm) 

Después de una extensa investigación y resultados escasos en Google para este problema, no he encontrado nada concluyente. Voy a probar otro equilibrador de carga para verificar si el problema es solo gunicorn.

De acuerdo, me encontré con esto en Flask / UWSGI / NGINX / Linux 14.04.

Buenas noticias para futuros lectores: pude resolver esto. Malas noticias: estoy bastante seguro de que este es un hack horrible.

Algunos códigos de prueba interesantes para probar que esto se bloqueará para siempre:

 @app.route('/spin-up') def spin_up(): import multiprocessing as mp def spin_forever(): while True: time.sleep(1) print('starting new process') p = mp.Process(target=spin_forever) print('created') p.start() print('started--generating result') return flask.render_template_string('awesome') 

Si llegas al punto final ‘/ spin-up’, el proceso se acelera y se cuelga para siempre. Bastante impresionante, ¿eh?

Las colas de mensajes básicas no funcionan a menos que esté completamente fuera de proceso (es decir, use una cola de mensajes que se ejecuta en un proceso diferente ya iniciado) o no valide el éxito (es decir, espere una respuesta ACK satisfactoria) .

La respuesta corta es que si intenta validar que su subproceso tuvo éxito, está en problemas. Estaba usando una cola de mensajes interna entre hilos, y si esperaba mi respuesta de “éxito”, el servidor Flask todavía se bloqueaba. P.ej,

 @app.route('/spin-up') def spin_up(): put_start_message_on_queue(): while True: if got_success_response_from_queue(): break time.sleep(0.1) return flask.render_template_string('awesome') 

Esto aún se cuelga (para siempre), así que en lugar de eso agregué un segundo comando a la cola de mensajes llamada ‘reinicio’:

 @app.route('/spin-up') def spin_up(): put_start_message_on_queue() while True: if got_success_message_from_queue(): break time.sleep(0.1) put_restart_message_on_queue() return flask.render_template_string('awesome') 

Debe asegurarse de que el reinicio_mensaje, cuando se recibe, elimine el proceso existente, luego realice una cantidad mínima de trabajo antes de iniciar el nuevo, posiblemente incluso insertando un

 time.sleep(0) 

en el manejador de mensajes. ESTO ES UN GRAN HACK, por lo que puedo decir, pero funciona de manera consistente, y siempre que el proceso pueda reiniciarse (perdón si ese no es el caso para usted …)

Reemplace el multiprocessing por multiprocessing.dummy gunicorn podría resolver el problema ya que tanto gunicorn como el multiprocessing son módulos de multiprocesamiento y puede causar problemas cuando intenta invocar múltiples procesos dentro de un solo proceso.

Mi progtwig también se colgó de manera similar. Gevent y Multiprocesamiento. El proceso no juega bien juntos, parece.