我正试图在Cedar堆栈上部署一个Sinatra流式SSE响应应用程序。不幸的是,尽管在开发中它运行得非常完美,但一旦部署到Heroku上,当调用连接时callback
或errback
从未被调用,导致连接池充满了过期的连接(因为服务器端仍在向它们发送数据,所以这些连接永远不会超时)。
来自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上连接似乎从未关闭。
foreman start
命令吗? - Shelvacu