【问题标题】: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 会出现故障,当我们尝试访问它时,它会引发异常。
为了解决这个问题,我们希望:
- 尝试每 15 秒更新一次
- 但如果它离线,使用旧值最多 5 分钟,每 15 秒左右重试一次
- 如果过期超过 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 造成冲击。