1. ホーム
  2. ruby

[解決済み] Ruby Net::HTTPの実行期限が切れた

2022-02-18 07:49:33

質問

Net::HTTPを使用して、以下のコードが、アクセスしたURLのウェブサーバーログに対応する応答が迅速に送信されたにもかかわらず、"実行期限切れ"というメッセージでStandardErrorから救出されることが、定期的にあります。 Webサーバーのログが5秒以上かかる応答を示している場合、私は通常、コードがTimeout::Errorから救出されるのを見ます。

以下のコードがStandardErrorで"execution expired"となるのはどのような場合でしょうか。 ではなく Timeout::Errorから救助する?

このコードは、比較的古い Ruby 1.9.3 で、新しいバージョンの Ruby をサポートしていないプラットフォームで、マルチスレッドプログラムで実行されています。 プログラムはマルチスレッドですが、表示されているコードはシングルスレッドでしか動作していません。

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

解決方法は?

これは、どのように rescue が動作します。のドキュメントページを見てください。 Exception クラスがあります。基本的には、一つの例外を継承した例外を多数作成し、その全てを親クラスでrescueを使って処理することができます。

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

このコードでは、すべてのタイプの例外を Exception がルートです(他の例外はそこから継承されます)。あなたの場合 Timeout::Error を継承しています。 RuntimeError を継承し、さらに StandardError :

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 ブロックを使ってコードを修正します。