超时不一致::超时和救援超时::错误行为

时间:2012-07-11 15:23:00

标签: ruby-on-rails timeout rescue

我正在使用Timeout::timeout(1)进行超过1秒的过程,但它偶尔会触发超时。如果是这样,rescue每次都会以不同的方式捕获它。以下是我的代码示例:

require 'timeout'
...
begin
  status = Timeout::timeout(1) {
    open(file_url) do |foo|
      feed = RSS::Parser.parse(foo)
      some_method_call(arg1, arg2)
      #other stuff
    end
  }
rescue Timeout::Error
  Rails.logger.debug "Timeout"
  return nil
rescue Exception => ex
  Rails.logger.debug "EXCEPTION - #{ex.message}"
  return nil
end

以下是我使用相同输入遇到的三种情况:

  • 流程运行至完成且耗时超过60秒
  • 处理超时并挂起,仅在execution expired
  • 中打印development.log
  • 处理超时,正确获救,在"Timeout"打印development.log,然后返回nil

为什么这么不一致?

更新

将超时减少到0.0001s后,进程会按预期一致地超时。似乎open(file_url)区块的开启时间超过1秒,尽管区块内的所有区域都超过1秒,但Timeout仅在开口本身花费的时间超过1秒时触发。

然而,这并没有解释execution expired例外情况。为了测试这一点,我将Timeout::timeout(0.0001)移到open块内。代码如下所示:

require 'timeout'
...
begin
  open(file_url) do |foo|
    status = Timeout::timeout(0.0001) do
      begin
        feed = RSS::Parser.parse(foo)
        some_method_call(arg1, arg2)
        #other stuff
      rescue Timeout::Error
        Rails.logger.debug "Timeout 2"
      rescue Exception => ex
        Rails.logger.debug "EXCEPTION 2 - #{ex.message}"
      end
    end
  end
rescue Timeout::Error
  Rails.logger.debug "Timeout"
  return nil
rescue Exception => ex
  Rails.logger.debug "EXCEPTION - #{ex.message}"
  return nil
end

现在,我一直在收到输出EXCEPTION 2 - execution expired。为什么这里没有触发Timeout::Error

2 个答案:

答案 0 :(得分:1)

你的内心

rescue Exception => ex
  Rails.logger.debug "EXCEPTION 2 - #{ex.message}"
end

阻止外部timeout阻止提升Timeout::Error

删除rescue语句应该可以解决问题。

如果您确实需要捕获任何异常,请将其替换为:

rescue StandardError => ex
  Rails.logger.debug "EXCEPTION 2 - #{ex.message}"
end

答案 1 :(得分:0)

内部(在Timeout块内)Timeout不使用Timeout :: Error。如果确实如此,那么每次花园式的救援都会抓住它,而你却不希望如此。因此它创建了一个新的Exception并使用它,因此希望能够完成所有正常的错误处理并实际使代码停止运行。

查看ruby200 / lib / ruby​​ / 2.0.0中的timeout.rb代码。它很短,而且非常有用。

特别是,您可以将自己的Exception作为Timeout :: timeout的第二个参数传递,Timeout将使用它。因此,如果您愿意,可以在代码中捕获它。

请注意,Logger当前捕获写入时发生的所有异常,并且不会重新引发,因此会中断Timeout。我已经提交了一份错误报告。