Я пытаюсь развернуть приложение ответа SSE с потоком Sinatra в стеке Cedar. К сожалению, пока он отлично работает в разработке, после развертывания в Heroku callback
или errback
никогда не вызывается при вызове соединения, что приводит к тому, что пул соединений заполняется устаревшими соединениями (которые никогда не выходят за пределы, поскольку данные все еще остаются отправленных им на стороне сервера.)
Информация о Relvant из документации Heroku:
Долгосрочные и потоковые ответы
Cedar поддерживает функции HTTP 1.1, такие как длительный опрос и потоковые ответы. Приложение имеет начальное 30-секундное окно для ответа на один байт обратно клиенту. Однако каждый байт, переданный после этого (либо полученный от клиента, либо отправленный вашим приложением), сбрасывает свернутое 55-секундное окно. Если в течение 55 секунд не будет отправлено никаких данных, соединение будет завершено.
Если вы отправляете потоковый ответ, например, с событиями, отправленными сервером, вам нужно будет обнаружить, когда клиент повесил трубку, и убедитесь, что ваш сервер приложений мгновенно закрывает соединение. Если сервер держит соединение открытым в течение 55 секунд без отправки каких-либо данных, вы увидите таймаут запроса.
Это именно то, что я хотел бы сделать - обнаружить, когда клиент повесил трубку, и быстро закрыть соединение. Однако что-то о слое маршрутизации Heroku, по-видимому, мешает Sinatra обнаруживать событие закрытия потока, как обычно.
Пример кода, который можно использовать для репликации:
require 'sinatra/base'
class MyApp < Sinatra::Base
set :path, '/tmp'
set :environment, 'production'
def initialize
@connections = []
EM::next_tick do
EM::add_periodic_timer(1) do
@connections.each do |out|
out << "connections: " << @connections.count << "\n"
end
puts "*** connections: #{@connections.count}"
end
end
end
get '/' do
stream(:keep_open) do |out|
@connections << out
puts "Stream opened from #{request.ip} (now #{@connections.size} open)"
out.callback do
@connections.delete(out)
puts "Stream closed from #{request.ip} (now #{@connections.size} open)"
end
end
end
end
Я добавил пример приложения http://obscure-depths-3413.herokuapp.com/, используя этот код, который иллюстрирует проблему. Когда вы подключаетесь, количество подключений будет увеличиваться, но когда вы отключитесь, они никогда не опускаются. (Полный источник демо с Gemfile и т.д. Находится на https://gist.github.com/mroth/5853993)
Я в конце концов пытаюсь отладить этот. Кто-нибудь знает, как это исправить?
P.S. Похоже, что была похожая ошибка в Sinatra но она была исправлена год назад. Также эта проблема возникает только при производстве в Heroku, но отлично работает при локальном запуске.
P.S.2. Это происходит при итерации по объектам соединений, например, добавление следующего кода:
EM::add_periodic_timer(10) do
num_conns = @connections.count
@connections.reject!(&:closed?)
new_conns = @connections.count
diff = num_conns - new_conns
puts "Purged #{diff} connections!" if diff > 0
end
Работает отлично на месте, но соединения никогда не появляются как закрытые на Heroku.