能否让faraday-http-cache在源站故障时返回缓存资源?
首先直接回应你的核心问题:现在faraday-http-cache已经原生支持stale-if-error指令,完全可以实现类似Cloudflare Always Online的功能——当CMS(源站)宕机或返回5xx错误时,返回缓存的过期内容。
一、当前推荐方案:使用stale-if-error
如果你使用的是较新版本的faraday-http-cache(大致v2.0.0及以上),已经内置了对RFC 5861中stale-if-error的支持。配置起来很简单,只需在缓存策略中添加该指令:
Faraday.new(url: 'your_cms_api_url') do |faraday| faraday.use :http_cache, store: Rails.cache, stale_if_error: 86400 # 允许过期缓存最多保留1天 faraday.adapter Faraday.default_adapter end
这里的stale_if_error参数指定了源站出错时,允许返回过期多久的缓存内容(单位为秒)。当CMS返回5xx错误、连接超时或不可达时,中间件会自动拿出符合条件的缓存内容返回,而非抛出错误。
二、旧版本的临时方案:max-stale是否仍有效?
你提到的2016年GitHub Issue里的max-stale方案,在未支持stale-if-error的旧版本faraday-http-cache中确实可作为临时替代,而且直到现在,这个方案依然有效——只是你需要接受它的局限性:
max-stale的原理是告知缓存中间件,即便缓存已过期,只要过期时长不超过指定秒数,就可以直接返回缓存,无需去源站验证。配置示例:
Faraday.new(url: 'your_cms_api_url') do |faraday| faraday.use :http_cache, store: Rails.cache faraday.headers['Cache-Control'] = 'max-stale=86400' # 接受最多过期1天的缓存 faraday.adapter Faraday.default_adapter end
但这个方案有个明显缺点:它是无条件接受过期缓存,不管源站是否正常。也就是说,哪怕源站正常运行,只要缓存过期时间在max-stale范围内,中间件也不会去源站拉取最新内容,这可能导致应用长时间使用过时数据。而stale-if-error是仅在源站出错时才使用过期缓存,源站正常时依然会获取最新内容,显然更符合你“CMS故障时 fallback 到缓存”的需求。
总结
- 若使用新版本faraday-http-cache,优先用
stale-if-error,这是最贴合需求的原生方案; - 若因特殊原因只能用旧版本,
max-stale方案依然可行,但要注意它的副作用; - 两种方案都需要确保缓存存储(比如Rails.cache)能持久化保存缓存内容,避免重启应用后缓存丢失。
内容的提问来源于stack exchange,提问作者jajavoli

