使用Net :: HTTP,我定期发现下面的代码从StandardError中救出“执行过期”消息,尽管从访问过的URL中显示的Web服务器日志显示相应的响应已快速发送。当Web服务器日志显示响应时间超过5秒时,我通常会看到来自Timeout :: Error的代码救援。
什么情况会导致下面的代码从StandardError抢救“执行过期”而不是从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
答案 0 :(得分:3)
这是因为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
块的顺序以修复代码。