Quantcast
Channel: Active questions tagged redis+ruby-on-rails - Stack Overflow
Viewing all articles
Browse latest Browse all 873

In Rails, is there a way to "short-circuit" out of a rescue_from?

$
0
0

I am trying to make a nice user-friendly failsafe recovery for Redis in Rails. I'm using the built in redis_cache_store and have reconnect_attempts set, but I would like to send the user to a custom error page in the event that Redis remains down, rather than have them be stuck on a nonresponsive page with no idea what is going on.

What I tried was to monkey-patch the failsafe method in RedisCacheStore by re-raising a new type of error, RedisUnavailableError, which I then have my application_controller catch and redirect_to a static 500 page.

Where this breaks down is that I would like my application to just stop after the redirect. In the byebug trace below, you can see that before the second-last block I've included, the redirect line is reached.

But it does not stop; I've included just the first of a long sequence of further methods invoked that eventually results in another attempt to write to Redis, which is still down, which then re-raises the same sequence of exceptions, which Rails then will not catch a second time (indeed even if it did, that would be an infinite loop).

So my question is: is there any way to get the rescue_from block to just stop and not continue triggering anything else after a certain line is reached?

Alternately, is there any way to on the fly "disable" Redis or change the cache store/settings to some nullary value in the rescue_from block so that anything further triggered won't try to talk to Redis?

    [40, 49] in (DELETED)/redis_failsafe.rb
       40:   rescue ::Redis::BaseConnectionError => e
       41:     byebug
       42:     handle_exception(exception: e, method: method, returning: returning)
       43:     returning
       44:     byebug
    => 45:     raise RedisUnavailableError
       46:     # Re-raise the exception when reconnect attempt fails, so our application controller can handle it.
       47:   end
       48: end
       49: 
    (byebug) c

    [INFO][15:50:51] [3cf7] [GET] [(DELETED):3000] [/suppliers] 
    ∙ Redirecting to 500 page due to: RedisUnavailableError

    [30, 39] in /(DELETED)/application_controller.rb
       30:   authorize_resource class: false
       31: 
       32:   rescue_from RedisUnavailableError do |exception|
       33:     byebug
       34:     Rails.logger.info "Redirecting to 500 page due to: #{exception.message}"
    => 35:     redirect_to '/500.html'
       36:     byebug
       37:   end
       38: 
       39:   rescue_from ActiveRecord::RecordNotFound do
    (byebug) n
    ∙ Redirected to http://(DELETED)/500.html
    Return value is: nil

    [32, 41] in /(DELETED)/application_controller.rb
       32:   rescue_from RedisUnavailableError do |exception|
       33:     byebug
       34:     Rails.logger.info "Redirecting to 500 page due to: #{exception.message}"
       35:     redirect_to '/500.html'
       36:     byebug
    => 37:   end
       38: 
       39:   rescue_from ActiveRecord::RecordNotFound do
       40:     render status: :not_found, plain: 'Not found'
       41:   end
    (byebug) n

    [51, 60] in /(DELETED)/rescuable.rb
       51:   def rescue_with_handler(exception, object: self, visited_exceptions: [])
       52:     visited_exceptions << exception
       53: 
       54:     if handler = handler_for_rescue(exception, object: object)
       55:       handler.call exception
    => 56:       exception
       57:     elsif exception
       58:       if visited_exceptions.include?(exception.cause)
       59:         nil
       60:       else
    (byebug) 

Viewing all articles
Browse latest Browse all 873

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>