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