最终没有找到任何好的解决方案,所以最终使用了这个:
# 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。