Python Flask, как определить, что клиент SSE отключается от интерфейса Javascript
Возможно, это проблема в Flask, нет способа обработать событие разъединения на стороне сервера.
В классе Response существует метод с именем "call_on_close", где мы можем добавить функцию без аргумента, например. on_close(), он будет запущен при вызове метода закрытия объекта ответа, но этого не происходит, когда я вызываю EventSource.close() со стороны клиента в Javascript.
код на стороне сервера:
from flask import Response
r = Response(stream(), ...)
r.call_on_close(on_close)
return r
def on_close():
print "response is closed!"
def stream():
... # subscribe to redis
for message in pubsub.listen():
....
yield 'data: %s\n\n' % message
на стороне клиента: добавьте обработчик выгрузки на страницу с SSE
$(window).unload(
function() {
sse.close();
}
}
Что-то не так?
Приветствуются любые предложения или решения с кодом!
Спасибо заранее!
Ответы
Ответ 1
У меня была аналогичная проблема с Rails Live Controllers. Проблема в том, что структура не обнаруживает, что соединение закрыто, пока оно не попытается отправить событие клиенту.
Один из подходов заключается в отправке клиенту периодических "сердечных" событий. В настоящее время я успешно использую это в проекте Rails с интервалом в 60 секунд. У меня есть отдельный поток, который "испускает" эти пульса в Redis, на который мой контроллер подписался.
Альтернативой поточному подходу является обертывание блока pubsub Redis таймаутом (опять же, скажем, 60 секунд). А затем отправьте событие heartbeat клиенту, а затем еще один вызов pubsub. Недостатком этого подхода является то, что вы можете пропустить мероприятие, пока вы не подписаны.
Здесь больше по подходу к потоку:
Redis + ActionController:: Живые потоки не умирают
Ответ 2
Генератор получает исключение GeneratorExit
, и, когда вы знаете, он выйдет. Например:
def stream():
try:
i = 0
while True:
yield 'Hello {}!'.format(i)
i += 1
time.sleep(1)
finally:
# Called after a GeneratorExit, cleanup here
i = 0
@app.route('/messages')
def messages():
return Response(stream(), content_type='text/event-stream')
Даст бесконечный поток "Hello!"
, и вы будете знать, когда это будет сделано, где вы можете запустить код очистки. Если ваш генератор блокирует поток, его нужно каким-то образом разблокировать (возможно, нажав на пустышку), чтобы генератор мог быть закрыт.