使用python flask流式传输时,查看进程未停止

时间:2014-05-15 18:47:21

标签: python flask

我使用一个简单的Flask应用程序和gunicorn的gevent worker来为服务器发送的事件提供服务。

要播放内容,请使用:

response = Response(eventstream(), mimetype="text/event-stream")

从redis中传输事件:

def eventstream():
    for message in pubsub.listen():
        # ...
        yield str(event)

部署:

gunicorn -k gevent -b 127.0.0.1:50008 flaskapplication

但是在使用了一段时间之后,即使没有人连接到服务器发送的事件流,我也会打开50个redis连接。

看来,就像视图没有终止一样,因为gunicorn是非阻塞的而pubsub.listen()是阻塞的。

我该如何解决这个问题?我应该限制gunicorn可能产生的进程数量,还是应该在一些超时后烧掉视图?如果可能,它应该在不活动时停止view / redis连接,而不断开仍连接到SSE流的用户。

2 个答案:

答案 0 :(得分:2)

您可以使用gunicorn运行-t <seconds>来指定工作人员的超时时间,如果他们静默几秒钟就会杀死他们,通常是30秒。我认为这应该适用于你的问题,但不完全确定。

从我所看到的情况来看,您似乎也可以重写您的工作人员以使用Timeout中的gevent

这可能类似于以下内容:

from gevent import Timeout

def eventstream():
    pubsub = redis.pubsub()
    try:
        with Timeout(30) as timeout:
            pubsub.subscribe(channel)
            for message in pubsub.listen():
                # ...
                yield str(event)
    except Timeout, t:
        if t is not timeout:
            raise
        else:
            pubsub.unsubscribe(channel)

This example有助于了解这应该如何运作。

答案 1 :(得分:0)

使用natdempk解决方案中的Timeout对象,最优雅的解决方案是发送心跳,以检测死连接:

while True:
    pubsub = redis.pubsub()
    try:
        with Timeout(30) as timeout:
            for message in pubsub.listen():
                # ...
                yield str(event)
                timeout.cancel()
                timeout.start()
    except Timeout, t:
        if t is not timeout:
            raise
        else:
            yield ":\n\n"  # heartbeat

请注意,您需要再次调用redis.pubsub(),因为redis连接在异常后丢失,您将收到错误NoneType object has no attribute readline