Gunicorn 与 gevent 不强制超时

Joh*_*etz 6 python wsgi flask uwsgi gunicorn

假设我有一个简单的烧瓶应用程序:

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"
Run Code Online (Sandbox Code Playgroud)

我可以使用 Gunicorn 运行它,超时时间为 5 秒:

gunicorn app:app -b 127.0.0.1:5000 -t 5
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,http://127.0.0.1:5000在 5 秒后超时:

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)
Run Code Online (Sandbox Code Playgroud)

现在,我想使用异步工作线程运行 Gunicorn,以允许 Web 服务器更有效地使用其可用资源,从而最大限度地利用时间,否则这些时间将被闲置以执行额外的工作。我正在使用 gevent,仍然有 5 秒的超时。

gunicorn app:app -b 127.0.0.1:5000 -t 5 -k gevent
Run Code Online (Sandbox Code Playgroud)

出乎意料的是,http://127.0.0.1:5000并没有超时:

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
Run Code Online (Sandbox Code Playgroud)

看起来这是gunicorn 的一个已知问题。超时仅适用于默认同步工作线程,不适用于异步工作线程:https ://github.com/benoitc/gunicorn/issues/2695


uWSGI 是gunicorn 的替代选项。我对此不太熟悉。看起来它的超时选项被调用harakiri并且可以使用 gevent 运行:

uwsgi --http 127.0.0.1:5000 --harakiri 5 --master -w app:app --gevent 100
Run Code Online (Sandbox Code Playgroud)

uWSGI 的超时有时会像预期的那样与 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 ...
Run Code Online (Sandbox Code Playgroud)

但其他时候它不会超时,所以它看起来很不稳定。


无论如何,是否可以使用带有异步工作线程的gunicorn来强制超时?如果没有,是否有任何其他 Web 服务器可以与异步工作线程强制执行一致的超时,类似于 uWSGI?

aar*_*ron 5

来自https://docs.gunicorn.org/en/stable/settings.html#timeout

\n
\n

沉默超过这么多秒的工人将被杀死并重新启动。

\n
\n
\n

对于非同步工作线程,这仅意味着工作进程仍在通信,并且与处理单个请求所需的时间长度无关。

\n
\n

因此,timeout\xe2\x80\x94 的设计很可能是工作超时,而不是请求超时。

\n

您可以使用子类GeventWorkerhandle_request()覆盖gevent.Timeout

\n
import gevent\nfrom gunicorn.workers.ggevent import GeventWorker\n\n\nclass MyGeventWorker(GeventWorker):\n\n    def handle_request(self, listener_name, req, sock, addr):\n        with gevent.Timeout(self.cfg.timeout):\n            super().handle_request(listener_name, req, sock, addr)\n
Run Code Online (Sandbox Code Playgroud)\n

用法:

\n
# gunicorn app:app -b 127.0.0.1:5000 -t 5 -k gevent\ngunicorn app:app -b 127.0.0.1:5000 -t 5 -k app.MyGeventWorker\n
Run Code Online (Sandbox Code Playgroud)\n