本文用以记录在flask-sse
使用中踩到的坑及解决方案。
当前主流的服务端推送方案
- 客户端短连接轮询
- websocket
- Server Send Event(SSE)
相较于轮询的方式,websocket和sse会稍显高级而不是无脑的轮询浪费网络资源。
在最近一次的方案选型中,我选择了sse,理由是websocket是双工,且需要单独的服务,而项目的需求仅是向客户端进行简单的推送信息,对比之下sse更显轻量且开发量更少。
使用过程中遇到的困难
flask-sse
redis连接释放问题
该库目前存在缺陷,当浏览器刷新或者网关断开重连时会重新new EventSource
,然而服务端并无法得知连接的断开,导致redis连接数会一直增加。
唯一释放的机会在于当再次收到推送信息,协程被唤醒并产生GeneratorExit
异常
因此代码中未对异常捕获,将错过最后一次释放reids连接的机会:1
2
3
4
5
def generator():
for message in self.messages(channel=channel):
yield str(message)
self.redis.connection_pool.disconnect()修改的代码已上传github,并提交merge,但是由于没有通过python2的测试用例导致未被合并(懒得适配),有兴趣的童鞋可以直接查看我fork提交的代码。
redis连接数查看
1
redis-cli -a pwd -h *.*.*.* info | grep client
程序阻塞问题
由于最开始使用之前未仔细看官方的实用说明和源码,发现uwsgi实用进程线程的启动模式,程序运行几次之后就阻塞了,最后发现正确的打开方式是使用协程的方式驱动http服务。另外还有一点现象,当使用flask自带的http服务器进行多线程
threaded=True
调试时redis连接能一次性释放掉,而当使用gunicorn+gevent方式运行时却没有一步到位的效果,原因是协程是异步的,一次最多
能唤醒对应进程数量的协程,所以redis的释放问题最终还是需要通过定时推送心跳包的方式解决,推荐使用celery
。网关超时问题
网关基本都会有超时设置,而浏览器的断线重连貌似对于504的异常并不起作用。
因此需要针对超时异常进行特殊处理。
这里给出nginx配置1
2
3
4
5
6
7
8
9
10
11
12
13
14location /eventsource {
include uwsgi_params;
uwsgi_pass eventsource-botbot-backend;
uwsgi_buffering off;
chunked_transfer_encoding off;
proxy_cache off;
access_log /var/log/nginx/eventsource_botbot.access.log;
error_page 504 =200 @eventsource-close-graceful;
}
location @eventsource-close-graceful {
add_header Content-Type text/event-stream;
return 200;
}注意
每个nginx网关就需要配置