开发者

Rescue_from doesn't rescue Timeout::Error from views or helpers

I have an around_filter in my application controller to encase all actions in a timeout block, so that actions fail before hitting the 30 second Heroku limit. I also have a rescue_from Timeout::Error to cleanly rescue these timeouts. Unfortunately, the rescue_from on开发者_开发技巧ly works some of the time.

It works fine if the timeout occurs while executing within the controllers, but fails to rescue if the timeout happens within a view or a helper.

Neither Interrupt nor SignalException, both of which Timeout::Error inherits from, rescue correctly either. However, rescuing Exception itself does rescue correctly within views and helpers.

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

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

def timeout_rescue
  # Rescued
end

Is there any other way to rescue Timeout::Error to get this working?


I ran into the same problem. I'm using Rails 3 + Rack::Timeout and trying to rescue_from in ApplicationController.

I ended up using this ...

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

UPDATE

I patched the rack-timeout gem to properly return Timeout::Error. It was a threading issue. Official gem has been updated: https://github.com/kch/rack-timeout

The new preferred method is below. In general, it's not a great idea to rescue from Exception and should be avoided if possible.

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

  def handle_timeout(exception)
    # handle timeout error
  end
end


When Timeout needs to raise an exception to terminate execution, it does not raise Timeout::Error. If it did, garden-variety rescues would trap it, and that's not what you want. Instead, it raises its own Exception that is derived from ::Exception, so it blows through any rescue except for rescue Exception. Or - you can pass your own Exception as the second parameter to Timeout::timeout, and that way you can rescue it. Note that Timeout will re-raise it.

Read the timeout.rb code (in ruby200/lib/ruby/2.0.0). It's quite short, pretty interesting and will tell you how it really works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜