运行Flask SSE示例时遭遇gevent.hub.LoopExit异常的问题
解决Flask SSE示例的gevent.hub.LoopExit异常问题
这个问题我之前也碰到过,核心是Flask和gevent的集成没做对,导致长连接的SSE请求触发了事件循环退出的异常。下面分点给你拆解原因和解决方案:
1. 最关键的遗漏:没打gevent猴子补丁
gevent要替换Python标准库中的同步IO(比如socket、threading)才能实现协程化的异步处理,而你直接运行示例代码的话,Flask还是在用原生的同步IO,这就会和gevent的事件循环冲突,最终抛出LoopExit异常。
你需要在代码的最开头加入猴子补丁的代码:
from gevent import monkey # 替换所有标准库的同步组件为gevent的异步实现 monkey.patch_all()
2. publish函数不需要提前声明为greenlet
你不用特意把publish改成greenlet,只要整个环境已经被猴子补丁处理,它的操作(比如遍历客户端列表发送消息)会在gevent的协程环境中自动适配,不会阻塞主线程。
3. 错误的启动方式:别用flask run
默认的flask run启动的是Flask自带的同步开发服务器,它不支持gevent的协程模型,无法正确处理SSE的长连接请求。你需要改用gevent的WSGI服务器来启动应用:
在你的stream.py末尾加上这段代码:
if __name__ == '__main__': from gevent.pywsgi import WSGIServer # 启动gevent的WSGI服务器,监听5000端口 http_server = WSGIServer(('0.0.0.0', 5000), app) print('Server running on http://0.0.0.0:5000') http_server.serve_forever()
然后直接用python stream.py启动服务,而不是env FLASK_APP=stream.py flask run。
为什么会出现LoopExit?
这个异常本质是gevent的事件循环在还没完成长连接任务时,被同步的服务器逻辑强制终止了。打猴子补丁让所有IO操作协程化,再用gevent的服务器接管请求处理,就能保证SSE的长连接在协程中持续运行,不会触发循环退出。
按照上面的步骤修改后,再用浏览器连接SSE端点,应该就能正常接收事件了。
内容的提问来源于stack exchange,提问作者Dov Grobgeld
相关产品推荐
相关产品推荐

