2

我们使用它从外部 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 分钟,然后才开始引发异常

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

4

1 回答 1

4

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

# 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。

于 2013-09-04T21:04:47.190 回答