Flask+gevent-SSE times out с nginx+uwsgi



Я пишу веб-приложение, основанное на Flask, gevent и Redis, которое использует события, отправленные сервером.



Я прошел через несколько вопросов на StackOverflow и обширный поиск в google, но не нашел подходящего ответа, который работает для меня, поэтому здесь я прошу помощи сообщества.

Проблема заключается в производственном стеке nginx+uwsgi: браузер регулярно получает обновления (и обновляется, как ожидается) в течение примерно 30 секунд. После этого время соединения истекает и браузер больше не получает никаких обновлений, пока страница не будет перезагружена вручную.



Поскольку все это прекрасно работает на localhost, со стандартным сервером разработки flask (соединение оживает после 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>


Это код, который я использую для возврата потоковых данных



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: 10000nndata: %snn' % event['data']

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


И, наконец, приложение выполняется так (DEBUG-True на 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()
552   1  

1 ответ:

После долгих часов работы с лог-файлами nginx и консолью firefox js оказалось, что конфигурации, показанные в вопросе, идеально подходят.

Проблема заключалась в перезагрузке страницы, это действие убивает и повторно инициализирует соединение, и поэтому команда повтора не имеет никакого эффекта.

После удаления этой инструкции обновления SSE работают как заклинание даже после долгого времени бездействия.

Теперь возникает вопрос, почему это сработало в более простой среде разработки стек: -)

Править

Действительно, через несколько дней связь все еще прерывается. Я сделал некоторые измерения времени и обнаружил, что интервал времени ожидания варьируется между примерно 30 секундами и несколькими минутами бездействия.

Мой вывод заключается в том, что стек выше в порядке, в то время как это соединение amazon EC2, которое истекает через некоторое переменное время бездействия, так как я все еще использую микро-экземпляр.

Окончательное исправление заключается в следующем JS фрагмент:

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

Страница перезагружается при разрыве соединения (независимо от причины). Повторные загрузки не должны происходить, когда сервер отправляет события часто.

Comments

    Ничего не найдено.