3

Rails 4.2.3 と Nokogiri を使用して Web サイトからデータを取得しています。サーバーから応答がないときにアクションを実行したいので、次のようにします。

begin
  content = open(url).read
  if content.lstrip[0] == '<'
    doc = Nokogiri::HTML(content)
  else
    begin
      json = JSON.parse(content)
    rescue JSON::ParserError => e
      content
    end
  end
rescue Net::OpenTimeout => e
  attempts = attempts + 1
  if attempts <= max_attempts
    sleep(3)
    retry
  end
end

これは、サーバーから 500 を取得することとは異なることに注意してください。TCP 接続が得られないか、サーバーが応答しない (または応答が得られないその他の理由) ため、応答がまったく得られない場合にのみ再試行します。私がそれをどのように持っているか以外に、この状況を考慮に入れるためのより一般的な方法はありますか? 私が考えていない例外の種類が他にもたくさんあるように感じます。

4

3 に答える 3

4

例外のレスキューに関しては、次のことを明確に理解することを目指す必要があります。

  • システムのどの行で例外が発生する可能性があるか
  • これらのコード行が実行されると、内部で何が起こっているのか
  • 基礎となるコードによってどのような例外が発生する可能性があるか

あなたのコードでは、コンテンツを取得している行は、ネットワーク エラーが発生する可能性がある行でもあります。

content = open(url).read

OpenURI モジュールのドキュメントにアクセスすると、 & friends を使用してNet::HTTP任意の URI のコンテンツを取得していることがわかります。

Net::HTTPを調達できるかを理解することは、実際には非常に複雑ですが、ありがたいことに、他の人がすでにこの作業を行っています。Thoughtbot の suspenders プロジェクトには、使用できる一般的なネットワーク エラーのリストがあります。これらのエラーの一部は、接続がリセットされるなど、考えていたものとは異なるネットワーク条件に関係していることに注意してください。それらも救済する価値があると思いますが、特定のニーズに合わせてリストを自由にトリミングしてください.

コードは次のようになります (少し単純化するために Nokogiri と JSON の部分は省略しています):

HTTP_ERRORS = [
  EOFError,
  Errno::ECONNRESET,
  Errno::EINVAL,
  Net::HTTPBadResponse,
  Net::HTTPHeaderSyntaxError,
  Net::ProtocolError,
  Timeout::Error,
]
MAX_RETRIES = 3

attempts = 0

begin
  content = open(url).read
rescue *HTTP_ERRORS => e
  if attempts < MAX_RETRIES
    attempts += 1
    sleep(2)
    retry
  else
    raise e
  end
end
于 2016-07-21T12:35:14.433 に答える
1

短時間後に例外を発生させるタイムアウトの使用について考えます。

MAX_RESPONSE_TIME = 2 # seconds
begin
  content = nil # needs to be defined before the following block
  Timeout.timeout(MAX_RESPONSE_TIME) do  
    content = open(url).read
  end

  # parsing `content`
rescue Timeout::Error => e
  attempts += 1
  if attempts <= max_attempts
    sleep(3)
    retry
  end
end
于 2016-07-20T20:22:05.043 に答える