2016-09-24 18 views
1

Net :: HTTPを使用して、以下のコードが、アクセスされたURLからのWebサーバーログが対応するURLを表示しているにもかかわらず、「実行期限切れ」のメッセージでStandardErrorから救済されます応答がすぐに送信されました。 Webサーバーのログに5秒以上かかる応答が表示されると、通常、Timeout :: Errorのコードレスキューが表示されます。Ruby Net :: HTTP実行の有効期限が切れました

以下のコードは、タイムアウト::エラーから救済されたの代わりに、 "実行期限切れ"のでStandardErrorからレスキューすることができますか?

このコードは、Rubyの新しいバージョンをサポートしていない比較的古くからのRuby 1.9.3のマルチスレッドプログラムで実行されています。プログラムはマルチスレッドですが、表示されるコードは単一のスレッド上でのみ実行されます。

begin 
    connection = Net::HTTP.new(uri.host, uri.port) 
    connection.open_timeout = 5 
    connection.read_timeout = 5 
    connection.start do |http| 
    request = Net::HTTP::Post.new("/reader_events") 
    request.body = body 
    response = http.request(request) 
    end 
rescue StandardError => std_error 
    log "error sending event to server: #{std_error}" 
rescue Timeout::Error => error 
    log "timeout sending event to server" 
end 
+1

他のレスキューブロックの前に 'レスキューTimeout :: Error'ブロックを置いてみてください。 Rubyでは、ほとんどの例外クラスはStandardErrorから継承しているので、Timeout :: Errorも同様です。その場合、エラーは一種のStandardErrorと一種のTimeout :: Errorの両方になります。そして、最初にマッチした 'rescue'ハンドラが勝ちます。 –

+0

@HenrikN良いキャッチ。 'Timeout :: Error.ancestors'は' StandardError'を継承しています。 – Casper

答えて

2

これは、どのようにrescueが機能するためです。 Exceptionクラスのドキュメントページをご覧ください。基本的には単一のものを継承し、多くの例外を作成し、親クラスで救助を使用して、それらのすべてを扱うことができます。

begin 
    ... 
rescue Exception => exception 
    ... 
end 

このコードはExceptionとして例外のすべてのタイプを救出しますルート(他の例外から継承されますそれ)。あなたのケースではStandardErrorから継承RuntimeErrorからTimeout::Error継承:

Timeout::Error.ancestors 
    => [Timeout::Error, RuntimeError, StandardError, Exception, Object, PP::ObjectMixin, Kernel, BasicObject] 

その結果、それはExceptionの一種である:

Timeout::Error.new.is_a?(StandardError) 
    => true 

あなたのケースでもう一つは、インタプリタから各rescue文をチェックするということです上から下へ最初にexceptionの種類がStandardErrorであるかどうかをチェックし、それ以降はrescueブロックに移動することを意味します。最も具体的なブロックから最も一般的なブロックまで、ブロックrescueを常にリストする必要があります。

rescueブロックの順番を変更してコードを修正してください。

+0

ああ、簡単な答えです。ありがとう! – davidgyoung

関連する問題