健壮地调用易断API:使用Net :: HTTP正确处理错误

|| 我将其作为一种似乎可靠的方法进行了破解,以调用不稳定的网络服务,该网络服务会给出超时,偶尔的名称解析或套接字错误等。 我以为我会把它放在这里,以防它很有用,或者更有可能被告知这样做的更好方法。
require \'net/http\'

retries = 5
begin
  url = URI.parse(\'http://api.flakywebservice.com\')
  http = Net::HTTP.new(url.host, url.port)
  http.read_timeout = 600  # be very patient
  res = nil
  http.start{|http|
    req = Net::HTTP::Post.new(url.path)
    req.set_form_data(params)  # send a hash of the POST parameters
    res = http.request(req)
  }
rescue Exception   # should really list all the possible http exceptions
  sleep 3
  retry if (retries -= 1) > 0
end

# finally, do something with res.body, like JSON.parse(res.body)
这个问题的核心是: 像这样调用网络服务时,我应该寻找什么例外? 这是尝试收集所有内容的尝试,但是似乎有比这更好的方法: http://tammersaleh.com/posts/rescuing-net-http-exceptions     
已邀请:
例外是有意义的,“ 1”为不同情况提供特定的例外。因此,如果您想以特定方式处理它们,则可以。 那篇文章说,处理那些特定的异常比处理2更好/更安全,这是真的。但是,
rescue Exception
与from4 itself本身不同,它等效于
rescue StandardError
,这是默认情况下在没有其他原因的情况下通常应执行的操作。 抢救顶级“ 6”将抢救整个执行堆栈中可能发生的所有事情,包括红宝石的某些部分用尽磁盘或内存,或者出现一些与系统相关的IO问题。 因此,至于“要挽救什么”,如果将代码更改为
rescue
,通常情况会更好。您将捕捉到所有想要的东西,而您却什么都不想要。但是,在这种特殊情况下,该人的列表中有一个唯一的异常不是StandardError的后代:
def parents(obj)
  ( (obj.superclass ? parents(obj.superclass) : []) << obj)
end

[Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse,
  Net::HTTPHeaderSyntaxError, Net::ProtocolError].inject([]) do |a,c|
  parents(c).include?(StandardError) ? a : a << c
end
# Timeout::Error < Interrupt

parents(Timeout::Error)
# [ Object, Exception < Object, SignalException < Exception,
#   Interrupt < SignalException, Timeout::Error < Interrupt ]
因此,您可以将代码更改为
rescue StandardError, Timeout::Error => e
,并且您将覆盖该文章中提到的所有情况,以及更多其他内容,但不会涉及您不想覆盖的内容。 (不需要
=> e
,但以下更多内容)。 现在,就您处理flakey API的实际技术而言,问题是,您要处理的API有什么问题?格式不正确的回复?没有回应?问题是在HTTP级别还是您返回的数据中? 也许您还不知道,或者您还不在乎,但是您知道重试可以使工作完成。在那种情况下,我至少建议记录异常。 Hoptoad有一个免费计划,并且有诸如like11ѭ之类的东西-我不记得那是否是确切的调用。或者,您可以使用
e.message
e.stacktrace
通过电子邮件发送或记录。     
尝试处理错误情况时,请注意,默认情况下,
Net::HTTP
将自动对某些HTTP动词进行重试。 net / http.rb#transport_request(Ruby v2.5.0)的源包括:
    if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
      count += 1
      @socket.close if @socket
      D \"Conn close because of error #{exception}, and retry\"
      retry
    end
因此,除非采取预防措施,否则在返回错误之前,
Net::HTTP
代码将对
IDEMPOTENT_METHODS_
中包含的所有HTTP谓词调用服务2x。 对于Ruby <2.5,我在Rails应用程序中想到的最好的事情是添加以下内容:
Net::HTTP::IDEMPOTENT_METHODS_.delete_if { true }
通过将
IDEMPOTENT_METHODS_
设置为空可以解决此问题,因此so21ѭ上的
#include?
将始终失败。 对于Ruby> = 2.5,
Net::HTTP
具有
#max_retries=
方法,应将其设置为
0
(当然,除非需要重试)。 在这里可以找到更多的背景和历史记录:Ruby用户:警惕Net :: HTTP     

要回复问题请先登录注册