Using python's Multiprocessing makes response hang on gunicorn Using python's Multiprocessing makes response hang on gunicorn flask flask

Using python's Multiprocessing makes response hang on gunicorn


Replace multiprocessing by multiprocessing.dummy might solve the issue since both gunicorn and multiprocessing are multiprocessing module and it might cause trouble when you try to invoke multiple processes inside of a single process.


OK, so I ran into this on Flask/UWSGI/NGINX/Linux 14.04.

Good news for future readers: I was able to resolve this.Bad news: I am pretty sure this is a horrible hack.

Some interesting test code to prove that this will hang forever:

@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')

If you hit the endpoint '/spin-up' it will spin up the process and hang forever. Pretty awesome, huh?

Basic message-queues don't work unless you go fully out-of-process (i.e., use a message queue running in an already-started different process) or don't validate the success (i.e., wait for a success ACK response).

The short answer is that if you attempt to validate that your sub-process succeeded, you are in trouble. I was using an internal message queue between threads, and if I waited for my "success" response, the Flask server would still hang. E.g.,

@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')

This still hangs (forever), so instead I added a second command to the message queue called 'restart':

@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')

You have to ensure that the restart_message, when received kills the existing process, then does a minimal amount of work before starting the new one, potentially even inserting a

time.sleep(0)

in the message handler. THIS IS A HUGE HACK as far as I can tell, but it works consistently, and so long as the process can be restarted (sorry if that's not the case for you...)


Replace multiprocessing by multiprocessing.dummy works. It will speed up the app in concurrent requests but not for one request