首页 > 解决方案 > 在 Rails 中,有没有办法从rescue_from 中“短路”?

问题描述

我正在尝试为 Rails 中的 Redis 进行用户友好的故障安全恢复。我正在使用内置redis_cache_store并已reconnect_attempts设置,但我想在 Redis 仍然关闭的情况下将用户发送到自定义错误页面,而不是让他们卡在不知道发生了什么的无响应页面上。

我尝试的是通过重新引发一种新型错误来猴子修补failsafe方法,然后我有我的捕获和静态 500 页面。RedisCacheStoreRedisUnavailableErrorapplication_controllerredirect_to

这个问题的原因是我希望我的应用程序在重定向后停止。在下面的byebug跟踪中,您可以看到在我包含的倒数第二个块之前,redirect已到达该行。

但它并没有停止;我只包含了调用的一长串进一步方法中的第一个,这些方法最终导致再次尝试写入 Redis,它仍然处于关闭状态,然后重新引发相同的异常序列,Rails 将不会再捕获时间(事实上,即使是这样,那将是一个无限循环)。

所以我的问题是:有没有办法让rescue_from块在到达某条线后 停止而不继续触发其他任何东西?

或者,是否有任何方法可以即时“禁用”Redis 或将缓存存储/设置更改为块中的某个空值,rescue_from以便进一步触发的任何内容都不会尝试与 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) 

标签: ruby-on-railsrubyexceptionredisrescue

解决方案


所以我的问题是:有没有办法让rescue_from块在到达某条线后停止而不继续触发其他任何东西?

是的,只需调用 rubybreak​​ 关键字。

break是为了完全打破一个块。next用于跳出块并继续进行下一次迭代(例如在while循环中)。它们非常有用。


推荐阅读