2016-09-24 35 views
1

使用Net :: HTTP,我定期发现下面的代码从StandardError以“执行过期”消息解救,尽管Web服务器从访问的URL记录日志显示相应的响应很快发送。当Web服务器日志显示的响应时间超过5秒钟时,我通常会看到Timeout :: Error代码挽救。Ruby Net :: HTTP执行过期

什么情况下会导致下面的代码从StandardError的抢救与“执行过期”的,而不是从超时::错误拯救?

这个代码运行在一个相对古老的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 
+1

试着把你的'救援超时::错误'块放在另一个救援块之前。在Ruby中,大多数异常类都继承自StandardError,所以如果Timeout :: Error也不会让我感到意外。如果是这样的话,那么错误将是一种StandardError和一种Timeout :: Error。第一个匹配的“救援”处理程序获胜。 –

+0

@HenrikN好的。打印'Timeout :: Error.ancestors'表明它确实从'StandardError'继承。 – Casper

回答

2

这是因为rescue的工作原理。看看Exception课程的文档页面。基本上你可以创建一个单一的一个继承了许多例外,并使用救援与父类处理所有的人:

begin 
    ... 
rescue Exception => exception 
    ... 
end 

此代码将拯救所有类型的异常为Exception的是根(其他例外,从继承它)。在你的情况从RuntimeErrorTimeout::Error继承从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块的顺序来修复代码。

+0

啊,简单的回答。谢谢! – davidgyoung