rack-timeout: Rescuing timeout errors in middleware
Hi - I’ve been running into a problem recently with Rack::Timeout’s errors killing Puma workers (since they now descend from Exception rather than StandardError and are not caught by most rescue blocks).
I’ve worked around this with a quick rack middleware to catch Rack::Timeout’s errors and wrap them in StandardErrors:
class TimeoutRecovery
def initialize(app, options = {})
@app, @options = app, options
end
# Rack::Timeout, as of 0.2.4, raises errors that descend from the Exception
# class when a request takes too long - however, this is a very strong
# exception level and will kill Puma's worker if we let it continue down the
# stack. So instead, catch it and wrap it in a recoverable StandardError.
class Error < StandardError; end
def call(env)
@app.call(env)
rescue Rack::Timeout::Error => e
raise Error, "Original Error: #{e.class.inspect}, #{e.message.inspect}, #{e.backtrace.inspect}"
end
end
It seems like this is something that Rack::Timeout should be doing, though. Unless I’ve missed something and this is actually a terrible idea. Sure, we should be avoiding long request times where possible, but when they come up they’re leaving Puma’s workers crashed and unable to serve requests at all until a restart.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 34 (14 by maintainers)
Commits related to this issue
- Update README.markdown fix note about error class descendancy. Via #76 — committed to zombocom/rack-timeout by kch 9 years ago
- Change error inheritance tree so Exceptions don't bubble up to the server. addresses #76, #73 — committed to zombocom/rack-timeout by deleted user 9 years ago
Yeah but that’s a known possibility and the solution to that is similar. Add an observer or rescue the error, close the connections, then probably re-raise.
I don’t know if there’s a one-size-fits-all solution here, and more and more I’m leaning against raising at all. Just provide a hook for people to do whatever they want with it? Then maybe provide some standard behaviours: log, raise, die… which I suppose one could do with observers already…