2014-01-07 140 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(); 
    } 

頁面重新加載當連接斷開(無論是什麼原因)。當服務器發送事件頻繁時,預計不會發生重新加載。

相關問題