私はこれを解決するのに真剣に苦労しています。
私は 2 つの Rails アプリを持っています。それらを Client と Service と呼びましょう。すべて非常にシンプルで通常の REST インターフェイスです。基本的なシナリオは次のとおりです。
- クライアントがサービスに対して POST /resources.json リクエストを行う
- サービスは、リソースを作成し、ID をクライアントに返すプロセスを実行します。
繰り返しますが、サービスの処理は非常に時間がかかり、数分かかる場合があるということだけです。その場合、サービスがリクエストを正しく処理し、200/201 で応答している間、リクエストが行われてから正確に 60 秒後にクライアントで EOFError が発生します ( ActiveResource::Base.timeout の設定に関係なく)。これは、ログに表示されるものです(時系列):
C 00:00:00: POST /resources.json
S 00:00:00: Received POST /resources.json => resources#create
C 00:01:00: EOFError: end of file reached
/usr/ruby1.8.7/lib/ruby/1.8/net/protocol.rb:135:in `sysread'
/usr/ruby1.8.7/lib/ruby/1.8/net/protocol.rb:135:in `rbuf_fill'
/usr/ruby1.8.7/lib/ruby/1.8/timeout.rb:62:in `timeout'
...
S 00:02:23: Response POST /resources.json, 201, after 143s
明らかに、サービスの応答はクライアントに届きませんでした。エラーをソケット レベルまで追跡し、シナリオをスクリプトで再現しました。そこでは、TCPSocket を開いてデータを取得しようとしました。私は何も要求していないので、何も返されず、要求は 70 秒後にタイムアウトするはずです (下部の完全なスクリプトを参照してください)。
Timeout::timeout(70) { TCPSocket.open(domain, 80).sysread(16384) }
これらは、いくつかのドメインの結果です。
www.amazon.com => Timeout after 70s
github.com => EOFError after 60s
www.nytimes.com => Timeout after 70s
www.mozilla.org => EOFError after 13s
www.googlelabs.com => Timeout after 70s
maps.google.com => Timeout after 70s
ご覧のとおり、70 秒間「待機」できるサーバーもあれば、接続を終了して EOFErrors を発生させたサーバーもありました。サービスに対してこのテストを行ったところ、(予想通り) 60 秒後に EOFError が発生しました。
なぜこれが起こるのか誰か知っていますか?これらを防止したり、サーバー側のタイムアウトを延長したりする方法はありますか? ソケットが閉じられた後もサービスは「機能」し続けるため、プロキシレベルで終了する必要があると思いますか?
すべてのヒントをいただければ幸いです。
PS: 完全なスクリプト:
require 'socket'
require 'benchmark'
require 'timeout'
def test_socket(domain)
puts "Connecting to #{domain}"
message = nil
time = Benchmark.realtime do
begin
Timeout::timeout(70) { TCPSocket.open(domain, 80).sysread(16384) }
message = "Successfully received data" # Should never happen
rescue => e
message = "Server terminated connection: #{e.class} #{e.message}"
rescue Timeout::Error
message = "Controlled client-side timeout"
end
end
puts " #{message} after #{time.round}s"
end
test_socket 'www.amazon.com'
test_socket 'github.com'
test_socket 'www.nytimes.com'
test_socket 'www.mozilla.org'
test_socket 'www.googlelabs.com'
test_socket 'maps.google.com'