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