我把这个整合在一起是一个看似强大的方法来调用一个片断的webservice,它提供了超时和偶尔的名称解析或套接字错误或者其他的错误.
我以为我会把它放在这里,万一它是有用的,或者更有可能被告知一个更好的方法来做到这一点.
我以为我会把它放在这里,万一它是有用的,或者更有可能被告知一个更好的方法来做到这一点.
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)
这个问题的核心是:
当打电话给这样一个webservice时,我应该寻找什么样的例外?
这是试图收集他们,但似乎有一个比这更好的方法:
http://tammersaleh.com/posts/rescuing-net-http-exceptions
解决方法
异常是有意义的,Net :: HTTP为不同类型的情况提供了特殊的例外.所以如果你想以特定的方式处理它们,你可以.
那篇文章说,处理这些特定的例外比处理救援异常更好/更安全,这是非常真实的.但是,拯救异常与救援本身不同,这相当于拯救了StandardError,如果你没有任何理由做任何事情,你通常应该通常执行此操作.
抢救顶级异常将会拯救整个执行堆栈中可能发生的任何事情,包括某些部分的ruby从磁盘或内存中运行,或者有一些模糊的与系统有关的IO问题.
所以,就“拯救什么”而言,如果你改变你的代码去拯救,你通常会更好.你会抓住你想要的所有东西,没有你不想要的东西.然而,在这种特殊情况下,那个家伙的列表中没有一个唯一的例外,它不是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 ]
所以你可以改变你的代码来拯救StandardError,Timeout :: Error => e,你会涵盖那篇文章中提到的所有案例,而不是你不想覆盖的内容. (=> e不是必需的,但下面更多).
现在,就您处理flakey API的实际技术而言,问题是,您正在处理的API有什么问题?格式不正确的回复?没有回应? HTTP级别的问题还是您要恢复的数据?
也许你还不知道,或者你还不在乎,但你知道重试往往完成工作.在这种情况下,我至少建议记录例外. Hoptoad有一个免费的计划,并有某种东西像Hoptoad.notify(e) – 我不记得如果这是确切的调用.或者您可以使用e.message和e.stacktrace通过电子邮件或登录.