通过故障转移进行Rails缓存提取

时间:2013-09-01 01:14:45

标签: ruby-on-rails caching memcached

我们使用它来从外部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 个答案:

答案 0 :(得分: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。