2014-01-07 76 views
6

我正在编写一个基于Flask,gevent和Redis的Web应用程序,它使用了Server Sent Events。Flask + gevent - SSE超时nginx + uwsgi

我已经经历了StackOverflow上的几个问题,并在谷歌上进行了广泛的搜索,但没有找到适合我的任何合适的答案,所以在这里我要求社区帮助。

问题出在生产堆栈nginx + uwsgi:浏览器定期收到更新(并按预期刷新)约30秒。之后,连接超时并且浏览器不再接收任何更新,直到手动重新加载页面。

由于整个事情在本地主机上完美工作,使用标准的烧瓶开发服务器(连接在30分钟空闲后活着),我很确定问题出在uwsgi/nginx配置上。我已经尝试了所有我能想到的nginx/uwsgi设置,但没有任何设置,它会在几秒钟后超时。

有没有人有线索?

这里有一些代码和配置。

nginx的相关生产设置:

location/{ 
include uwsgi_params; 
uwsgi_pass unix:/tmp/myapp.sock; 
uwsgi_param UWSGI_PYHOME /srv/www/myapp/venv; 
uwsgi_param UWSGI_CHDIR /srv/www/myapp; 
uwsgi_param UWSGI_MODULE run; 
uwsgi_param UWSGI_CALLABLE app; 
uwsgi_buffering off; 
proxy_set_header Connection ''; 
proxy_http_version 1.1; 
chunked_transfer_encoding off; 
proxy_cache off; 
} 

uwsgi生产设置

[uwsgi] 
base = /srv/www/myapp 
app = run 
home = %(base)/venv 
pythonpath = %(base) 
socket = /tmp/%n.sock 
gevent = 100 
module = %(app) 
callable = app 
logto = /srv/www/myapp-logs/uwsgi_%n.log 

这是模板执行订阅频道(暂时的JavaScript,模板只是刷新整个页面当服务器推送一些数据时)

<script type="text/javascript"> 

var eventOutputContainer = document.getElementById("event"); 
var evtSrc = new EventSource("/movers/monitor"); 

evtSrc.onmessage = function(e) { 
    console.log(e.data); 
    location.reload(); 
    //eventOutputContainer.innerHTML = e.data; 
}; 
</script> 

This是我用返回流数据

from myapp import redislist 
from flask import Response, Blueprint, stream_with_context 

movers = Blueprint('movers', __name__, url_prefix='/movers') 
r = redislist['r'] 

@movers.route("/monitor") 
def stream_movers(): 
    def gen(): 
     pubsub = r.pubsub() 
     pubsub.subscribe('movers-real-time') 
     for event in pubsub.listen(): 
      if event['type'] == 'message': 
       yield 'retry: 10000\n\ndata: %s\n\n' % event['data'] 

    return Response(stream_with_context(gen()), direct_passthrough=True, mimetype="text/event-stream") 

,最后应用程序是这样执行的代码(DEBUG为真在localhost)

from myapp import app 
from gevent.wsgi import WSGIServer 

if __name__ == '__main__': 
    DEBUG = True if app.config['DEBUG'] else False 
    if DEBUG: 
     app.run(debug=DEBUG, threaded=True) 
     app.debug = True 
     server = WSGIServer(("", 5000), app) 
     server.serve_forever() 
    else: 
     server = WSGIServer("", app) 
     server.serve_forever() 

回答

3

上nginx的日志文件和Firefox的js控制台长时间后,结果证明问题中显示的配置非常好。

问题是页面重新加载,此操作杀死并重新初始化连接,因此重试命令没有任何影响。

删除该指令后,即使长时间不活动,SSE更新仍然像魅力一样工作。

现在的问题是,为什么这个工作更简单的开发环境堆栈:-)

编辑

事实上,几天后出来,连接仍倍。我已经做了一些时间测量,发现超时间隔在30秒和几分钟不活动之间是可变的。

我的结论是,上面的堆栈是好的,而它是亚马逊EC2连接,在某些变量不活动时间后过期,因为我仍在使用微型实例。

最终的解决方法是以下JS片段:

evtSrc.onerror = function(e) { 
     location.reload(); 
    } 

页面重新加载当连接断开(无论是什么原因)。当服务器发送事件频繁时,预计不会发生重新加载。

相关问题