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.
精彩评论