Ruby Net :: HTTP执行已过期

时间:2016-09-24 20:57:51

标签: ruby net-http

使用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

1 个答案:

答案 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块的顺序以修复代码。