ruby - Heroku 上的 Sinatra/Thin 未检测到 HTTP 流连接 (SSE) 客户端断开连接

标签 ruby heroku sinatra thin http-streaming

我正在尝试在 Cedar 堆栈上部署 Sinatra 流式 SSE 响应应用程序。不幸的是,虽然它在开发中完美运行,但一旦部署到 Heroku,callbackerrback 永远不会在调用连接时被调用,导致连接池被陈旧的连接填满(永远不会超时,因为数据仍在服务器端发送给他们。)

来自 Heroku 文档的相关信息:

Long-polling and streaming responses

Cedar supports HTTP 1.1 features such as long-polling and streaming responses. An application has an initial 30 second window to respond with a single byte back to the client. However, each byte transmitted thereafter (either received from the client or sent by your application) resets a rolling 55 second window. If no data is sent during the 55 second window, the connection will be terminated.

If you’re sending a streaming response, such as with server-sent events, you’ll need to detect when the client has hung up, and make sure your app server closes the connection promptly. If the server keeps the connection open for 55 seconds without sending any data, you’ll see a request timeout.

这正是我想要做的——检测客户端何时挂断,并立即关闭连接。然而,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 )

我无能为力地试图调试这个。有人知道怎么解决吗?

附言似乎有一个 similar bug in Sinatra但它在一年前就修好了。此外,此问题仅发生在 Heroku 的生产环境中,但在本地运行时工作正常。

附注 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 上从未显示为已关闭。

最佳答案

更新:在直接与 Heroku 路由团队(他们很棒!)合作后,这个问题现在已在他们的新路由层中得到修复,并且应该可以在任何平台上正常工作。

关于ruby - Heroku 上的 Sinatra/Thin 未检测到 HTTP 流连接 (SSE) 客户端断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17285961/

相关文章:

ruby - 即使是简单的页面也需要 Rails 中的路由吗?

heroku - 将我的 Heroku 应用程序从免费升级到业余爱好

.net - 是否有类似于 Ruby 的 Sinatra 的 .NET 框架?

deployment - therubyracer 无法在 heroku 上构建

ruby-on-rails - Redis::CannotConnectError(连接到本地主机上的 Redis 时出错:6379(Errno::ECONNREFUSED)):

javascript - Ruby:接收并打印 JSON 对象

ruby - 通过 Sinatra 应用程序将选项传递给 rackup

ruby - 异步运行 Sinatra 服务器和子进程

javascript - 在 Rails 应用程序中将 Web 应用程序单独作为 'V' ?

ruby - 将正整数转换为负整数