【问题标题】:Ruby Net::HTTP execution expiredRuby Net::HTTP 执行过期
【发布时间】:2016-09-24 20:57:51
【问题描述】:

使用 Net::HTTP,我会定期发现下面的代码从 StandardError 中救出并显示“执行已过期”消息,尽管来自访问 URL 的 Web 服务器日志显示相应的响应已快速发送。当 Web 服务器日志显示响应时间超过 5 秒时,我通常会看到来自 Timeout::Error 的代码救援。

什么情况下会导致下面的代码以“执行已过期”而不是从 Timeout::Error 中挽救 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

【问题讨论】:

  • 尝试将您的 rescue Timeout::Error 块放在另一个救援块之前。在 Ruby 中,大多数异常类都继承自 StandardError,所以如果 Timeout::Error 也是如此,我不会感到惊讶。如果是这种情况,那么错误将是一种 StandardError 和一种 Timeout::Error。第一个匹配的 rescue 处理程序获胜。
  • @HenrikN 很好。打印Timeout::Error.ancestors 表明它确实继承自StandardError

标签: ruby net-http


【解决方案1】:

这是因为rescue 的工作原理。查看Exception 类的文档页面。基本上,您可以创建许多继承自一个异常的异常,并使用具有父类的救援来处理所有异常:

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

此代码将拯救所有类型的异常,因为Exception 是根(其他异常继承自它)。在您的情况下,Timeout::Error 继承自 RuntimeError,而 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 块的顺序以修复代码。

【讨论】:

  • 啊,简单的回答。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-09-14
  • 1970-01-01
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 2014-05-19
相关资源
最近更新 更多