3

我的应用程序控制器中有一个 around_filter,用于将所有操作包含在超时块中,以便操作在达到 30 秒 Heroku 限制之前失败。我还有一个 rescue_from Timeout::Error 来彻底挽救这些超时。不幸的是,rescue_from 只在某些时候有效。

如果在控制器中执行时发生超时,它可以正常工作,但如果超时发生在视图或助手中,则无法救援。

Timeout::Error 继承自的 Interrupt 和 SignalException 都不能正确救援。但是,救援异常本身确实在视图和助手中正确救援。

around_filter :timeout
rescue_from Timeout::Error, :with => :timeout_rescue

def timeout
  Timeout::timeout(10){
    yield 
  }
end

def timeout_rescue
  # Rescued
end

有没有其他方法可以挽救 Timeout::Error 以使其正常工作?

4

2 回答 2

4

我遇到了同样的问题。我正在使用 Rails 3 + Rack::Timeout 并尝试在 ApplicationController 中进行救援。

我最终使用了这个......

rescue_from Exception do |exception|
  if exception.is_a?(Timeout::Error) || /execution expired/ =~ exception.message
    # rescued from timeout error
  end
  raise
end

更新

我修补了 rack-timeout gem 以正确返回 Timeout::Error。这是一个线程问题。官方 gem 已更新:https ://github.com/kch/rack-timeout

新的首选方法如下。一般来说,从异常中拯救不是一个好主意,如果可能的话应该避免。

class ApplicationController < ActionController::Base
  rescue_from Timeout::Error, with: :handle_timeout

  def handle_timeout(exception)
    # handle timeout error
  end
end
于 2011-07-07T22:19:41.750 回答
1

当 Timeout 需要引发异常终止执行时,它不会引发 Timeout::Error。如果是这样,普通救援会困住它,这不是你想要的。相反,它引发了自己的从 ::Exception 派生的异常,因此它会排除除救援异常之外的任何救援。或者 - 你可以将你自己的异常作为第二个参数传递给 Timeout::timeout,这样你就可以拯救它。请注意,超时将重新引发它。

阅读 timeout.rb 代码(在 ruby​​200/lib/ruby/2.0.0 中)。它很短,很有趣,会告诉你它是如何工作的。

于 2013-11-16T04:36:25.557 回答