Let's say I have a simple flask app:
import time
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
for i in range(10):
print(f"Slept for {i + 1}/{seconds} seconds")
time.sleep(1)
return "Hello world"
I can run it with gunicorn with a 5 second timeout:
gunicorn app:app -b 127.0.0.1:5000 -t 5
As expected, http://127.0.0.1:5000 times out after 5 seconds:
Slept for 1/10 seconds
Slept for 2/10 seconds
Slept for 3/10 seconds
Slept for 4/10 seconds
Slept for 5/10 seconds
[2022-07-07 22:45:01 -0700] [57177] [CRITICAL] WORKER TIMEOUT (pid:57196)
Now, I want to run gunicorn with an async worker to allow the web server to use its available resources more efficiently, maximizing time that otherwise would be spent idling to do additional work instead. I'm using gevent, still with a timeout of 5 seconds.
gunicorn app:app -b 127.0.0.1:5000 -t 5 -k gevent
Unexpectedly, http://127.0.0.1:5000 does NOT time out:
Slept for 1/10 seconds
Slept for 2/10 seconds
Slept for 3/10 seconds
Slept for 4/10 seconds
Slept for 5/10 seconds
Slept for 6/10 seconds
Slept for 7/10 seconds
Slept for 8/10 seconds
Slept for 9/10 seconds
Slept for 10/10 seconds
Looks like this is a known issue with gunicorn. The timeout only applies to the default sync worker, not async workers: https://github.com/benoitc/gunicorn/issues/2695
uWSGI is an alternate option to gunicorn. I'm not as familiar with it. Looks like its timeout option is called harakiri and it can be run with gevent:
uwsgi --http 127.0.0.1:5000 --harakiri 5 --master -w app:app --gevent 100
uWSGI's timeout sometimes works as expected with gevent:
Slept for 1/10 seconds
Slept for 2/10 seconds
Slept for 3/10 seconds
Slept for 4/10 seconds
Slept for 5/10 seconds
Thu Jul 7 23:20:59 2022 - *** HARAKIRI ON WORKER 1 (pid: 59836, try: 1) ***
Thu Jul 7 23:20:59 2022 - HARAKIRI !!! worker 1 status !!!
Thu Jul 7 23:20:59 2022 - HARAKIRI [core 99] 127.0.0.1 - GET / since 1657261253
Thu Jul 7 23:20:59 2022 - HARAKIRI !!! end of worker 1 status !!!
DAMN ! worker 1 (pid: 59836) died, killed by signal 9 :( trying respawn ...
But other times it doesn't time out so it appears to be pretty flaky.
Is there anyway to enforce a timeout using gunicorn with an async worker? If not, are there any other web servers that enforce a consistent timeout with an async worker, similar to uWSGI?
from Gunicorn with gevent does not enforce timeout
No comments:
Post a Comment