我正在使用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
以下是我使用相同输入遇到的三种情况:
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
?
答案 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。我已经提交了一份错误报告。