Using python's Multiprocessing makes response hang on gunicorn

限于喜欢 提交于 2019-12-03 07:23:33

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...)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!