处理Rails.cache.fetch中的错误

时间:2013-11-14 04:50:18

标签: ruby-on-rails caching ruby-on-rails-4

我正在使用Rails.cache来缓存来自API的响应:

Rails.cache.fetch("key") do 
  api.get "/api/data"
  api.body
end

API不是很可靠,偶尔我会收到500错误。我想避免缓存500响应。

Rails.cache.fetch("key") do 
  api.get "/api/data"
  if api.body.meta.status == 500
    # Bail out, Goose!
  end
  api.body
end

我宁愿不提出异常。没有缓存的“拯救”块的最佳方法是什么?

3 个答案:

答案 0 :(得分:2)

我自己也碰到了这个,看起来break会解决我们的问题。我只是在本地对memory_store和dalli_store进行了测试,它避免了缓存块。所以对于你的例子,尝试这样的事情:

Rails.cache.fetch("key") do 
  api.get "/api/data"
  break if api.body.meta.status == 500
  api.body
end

作为旁注,如果使用dalli_store,它将不会缓存nil值,因此您只能从块中返回nil。

答案 1 :(得分:0)

这是我的解决方案:

 module CacheExtensions
  class << self
    # This allows caching with an expiration, but if there is an exception thrown from the block that produces
    # the cache value, it uses the old value from the cache, retrying occasionally. The trick is to
    # not put an expiration on the cache value, but on a separate generated key, because Rails.cache.read honors
    # expirations set earlier. I'm surprised Rails.cache.fetch doesn't just handle this.
    #
    # key - the cache key to read and update if needed
    # expiration - how long the key should be good for under normal circumstances
    # retry_expiration - how long between retries if the block raises an exception. if expiration is long, you may want to
    # make this shorter.
    # block - should return the updated value, or raise an exception if it can't be retrieved
    #
    # Inspired by https://github.com/ReliveRadio/reliveradio-website/blob/4874cf4158361c73a693e65643d9e7f11333d9d6/app/helpers/external_api_helper.rb
    def fetch_with_rescue(key, expiration, retry_expiration)
      freshness_key = 'ExpirationFor_' + key
      result = Rails.cache.read(key)
      freshness_result = Rails.cache.read(freshness_key)

      if freshness_result.blank? || result.blank?
        begin
          result = yield
          Rails.cache.write(key, result)
          Rails.cache.write(freshness_key, 'fresh', expires_in: expiration)
        rescue StandardError => error
          Rails.cache.write(freshness_key, 'retrying', expires_in: retry_expiration)
          Rails.logger.error("Got error #{error} attempting to update cache #{key}. Using saved value for #{retry_expiration} additional time.")
        end
      end

      return result
    end
  end
end

答案 2 :(得分:0)

在这种情况下,在大多数情况下,我不会使用访存。

获取使您可以使用异常处理作为唯一的流控制机制(!)来处理所有流控制情况。

相反,请使用高速缓存的读取和写入方法,并使用正常的流控制来实现所需的行为。 Fetch快速而有趣,但是伴随着额外的负担,一旦必须真正支持所编写的软件,您就不会满意。