我正在尝试在Cedar堆栈上部署Sinatra流式SSE响应应用程序。不幸的是,虽然它在开发中完美运行,但一旦部署到Heroku,callback
或errback
在调用连接时永远不会被调用,导致连接池被填满过时的连接(永远不会超时,因为数据仍在服务器端发送给他们。)
来自Heroku文档的Relvant信息:
长轮询和流媒体响应
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。似乎有一个similar bug in 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上的连接永远不会显示为关闭。
答案 0 :(得分:2)
更新:直接与Heroku路由团队合作(他们是伟大的人!),现在已在新的路由层中修复,并且可以在任何平台上正常运行。
答案 1 :(得分:1)
我会在周期性时间内手动发送活动信号,如果收到消息,客户端应该回复。
请看这个简单的聊天实现https://gist.github.com/tlewin/5708745来说明这个概念。
应用程序使用简单的JSON协议与客户端通信。当客户端收到alive: true
消息时,应用程序回发响应,服务器存储上次通信时间。