Cedar スタックに Sinatra ストリーミング SSE 応答アプリケーションをデプロイしようとしています。残念ながら、開発中は完全に機能しますが、Heroku にデプロイされると、接続が呼び出されたときに呼び出されなかっcallback
たりerrback
、接続プールが古い接続でいっぱいになったりします (サーバー上でデータがまだ送信されているため、タイムアウトすることはありません)。側。)
Heroku ドキュメントからの関連情報:
ロングポーリングとストリーミング レスポンス
Cedar は、ロング ポーリングやストリーミング レスポンスなどの HTTP 1.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にあります)
私はこれをデバッグしようとしています。誰でもそれを修正する方法を知っていますか?
PS Sinatra にも同様のバグがあったようですが、1 年前に修正されました。また、この問題は Heroku の本番環境でのみ発生しますが、ローカルで実行すると問題なく動作します。
PS2。これは、次のコードを追加するなど、接続オブジェクトを反復処理するときにも発生します。
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 では接続が閉じているようには見えません。