使用gunicorn进行流式传输

6 投票
3 回答
5902 浏览
提问于 2025-04-18 00:30

我正在尝试从一个flask/gunicorn服务器进行数据流传输:

while (True):
    result = json.dumps(tweetQueue.get())
    yield result

但是,在流传输进行到30秒的时候,gunicorn会自动断开我的连接,导致流传输停止。我该如何设置超时时间,让服务器发布新数据到流中时可以重置这个超时时间,这样流就不会被终止呢?

谢谢!

3 个回答

0

Gunicorn 的工作进程会向主进程发送“消息”,告诉它们自己还活着(可以查看 这个链接)。不过,这种消息在处理响应的时候是不会发送的(比如可以查看 这个链接)。所以,如果处理响应的时间超过了设定的时间限制,主进程就会把这个工作进程杀掉。

0

可以考虑使用内置的 BaseHTTPServer,而不是 gunicorn。下面这个例子在同一个端口上启动了100个处理线程,每个处理线程都是通过 BaseHTTPServer 启动的。它可以很好地进行数据流传输,支持在一个端口上同时处理多个连接,而且通常运行速度是 gunicorn 的两倍。如果你需要的话,还可以把你的连接加上 SSL 加密。

import time, threading, socket, SocketServer, BaseHTTPServer

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        if self.path != '/':
            self.send_error(404, "Object not found")
            return
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()

        # serve up an infinite stream
        i = 0
        while True:
            self.wfile.write("%i " % i)
            time.sleep(0.1)
            i += 1

# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)

# Launch 100 listener threads.
class Thread(threading.Thread):
    def __init__(self, i):
        threading.Thread.__init__(self)
        self.i = i
        self.daemon = True
        self.start()
    def run(self):
        httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)

        # Prevent the HTTP server from re-binding every handler.
        # https://stackoverflow.com/questions/46210672/
        httpd.socket = sock
        httpd.server_bind = self.server_close = lambda self: None

        httpd.serve_forever()
[Thread(i) for i in range(100)]
time.sleep(9e9)

如果你还是想使用 gunicorn,记得把它(还有所有相关的包:wsgi、gevent、flask)放在一个虚拟环境(virtualenv)里,这样可以避免和其他软件发生冲突。

11

我在做了一些研究后,决定回答我自己的问题。

gunicorn server:app -k gevent

这里使用了异步工作者,这种方式的好处是可以在处理请求时使用 Connection: keep-alive。这样一来,请求就可以一直保持连接,不会中断。

撰写回答