我正在使用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
我宁愿不提出异常。没有缓存的“拯救”块的最佳方法是什么?
答案 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快速而有趣,但是伴随着额外的负担,一旦必须真正支持所编写的软件,您就不会满意。