Flask + gevent - время ожидания SSE истекает с nginx + uwsgi

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

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

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

Поскольку все это отлично работает на localhost, со стандартным сервером разработки фляги (соединение работает после 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: 10000\n\ndata: %s\n\n' % 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()

person user1981924    schedule 07.01.2014    source источник


Ответы (1)


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

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

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

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

РЕДАКТИРОВАТЬ

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

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

Последнее исправление - это следующий фрагмент JS:

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

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

person user1981924    schedule 11.01.2014