【问题标题】:Rails cache fetch with failover带故障转移的 Rails 缓存获取
【发布时间】:2013-09-04 10:44:00
【问题描述】:

我们使用它从外部 API 获取值:

def get_value
  Rails.cache.fetch "some_key", expires_in: 15.second do
    # hit some external API
  end
end

但有时外部 API 会出现故障,当我们尝试访问它时,它会引发异常。

为了解决这个问题,我们希望:

  1. 尝试每 15 秒更新一次
  2. 但如果它离线,使用旧值最多 5 分钟,每 15 秒左右重试一次
  3. 如果过期超过 5 分钟,则只有开始引发异常

是否有一个方便的包装器/库或者什么是一个好的解决方案?我们可以编写一些自定义的代码,但它似乎是一个足够常见的用例,应该有一些经过实战测试的东西。谢谢!

【问题讨论】:

    标签: ruby-on-rails caching memcached


    【解决方案1】:

    最终没有找到任何好的解决方案,所以最终使用了这个:

    # This helper is useful for caching a response from an API, where the API is unreliable
    # It will try to refresh the value every :expires_in seconds, but if the block throws an exception it will use the old value for up to :fail_in seconds before actually raising the exception
    
    def cache_with_failover key, options=nil
      key_fail = "#{key}_fail"
      options              ||= {}
      options[:expires_in] ||= 15.seconds
      options[:fail_in]    ||= 5.minutes
    
      val = Rails.cache.read key
      return val if val
    
      begin
        val = yield
        Rails.cache.write key,      val, expires_in: options[:expires_in]
        Rails.cache.write key_fail, val, expires_in: options[:fail_in]
        return val
      rescue Exception => e
        val = Rails.cache.read key_fail
        return val if val
        raise e
      end
    end
    
    
    
    # Demo
    fail = 10.seconds.from_now
    a = cache_with_failover('test', expires_in: 5.seconds, fail_in: 10.seconds) do
      if Time.now < fail
        Time.now
      else
        p 'failed'
        raise 'a'
      end
    end
    

    更好的解决方案可能会在第一次失败后以指数方式回退重试。正如目前所写的那样,它会在第一次失败后重试(在产量中)对 api 造成冲击。

    【讨论】:

      猜你喜欢
      • 2012-07-30
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-07
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多