Add stale-while-revalidate support with on_stale refresh hook#139
Conversation
…ook to trigger refresh
|
Hi @georgeguimaraes 👋 Curious if you've had some time to look at this PR. I'm a staff developer at Shopify working in their Carts team, we're currently building out the UCP agentic checkout protocol (see here). We make heavy use of this gem and would like to add an optional hook for the stale-while-revalidate directive. This change implements the stale window calculation and triggering of a new optional block for revalidation. Let me know if you have any questions, or if I can make any useful amendments -- Thanks! |
|
cc @garaujodev |
|
Thanks!! ❤️ 💚 💙 💛 💜 I'll be honest with you, when we created this gem, stale-while-revalidate was the reason since we had to implement this every time in some codebases. However, plans change :) Thanks a lot! |
|
let me cook a new release |
|
Thanks @georgeguimaraes ! |
Summary
Cache-Control: stale-while-revalidate=<seconds>directive so stale cache entries can still be served during a bounded grace window.:on_stalecallback hook (proc.call(request:, env:, cached_response:)) that runs when a stale response is served, enabling callers to trigger asynchronous cache refreshes.NOTE: This change does not trigger any async fetch when a request arrives in the stale period, it only calls your own code via the
on_stalehook. It is therefore up to the developer to provide their own async fetching method.Related issue: #84
Why
Today, once a cached response becomes stale, the middleware must synchronously revalidate it before responding. That is correct for strict freshness, but it can increase latency and reduce resiliency for endpoints where slightly stale data is acceptable.
stale-while-revalidateis a standard HTTP cache directive that allows a better tradeoff:See this explanation for more info, and this diagram.
This PR adds that behavior while preserving existing semantics for non-SWR responses.
How it works
1) Parse SWR directive
Faraday::HttpCache::CacheControlnow exposes#stale_while_revalidate.2) Determine SWR eligibility
Faraday::HttpCache::Responsenow exposes:#stale_while_revalidate?→ true when response is stale but still inside SWR window,#stale_while_revalidate→ parsed grace window in seconds.3) Middleware request flow
Faraday::HttpCachenow accepts:on_stale(or an equivalent init block).#process, behavior is now::stale, invokeon_stalecallback,must_revalidatepath (unchanged).4) Callback contract
When serving a stale response in the SWR window, middleware invokes:
on_stale.call(request:, env:, cached_response:)request:Faraday::HttpCache::Requestenv: currentFaraday::Envcached_response:Faraday::HttpCache::ResponseCallback errors are rescued and logged, so they do not break response serving.
5) Instrumentation/logging
:staleto cache statuses so instrumentation can distinguish SWR-served requests from fresh/valid hits.Tests
Added/updated coverage for:
CacheControlSWR parsing,:stale.Also added test server endpoints to exercise SWR flows.
Docs and example
:on_staleusage and callback arguments,:staleinstrumentation status.examples/stale_while_revalidate.rbdemonstrating stale serving and background refresh triggering.Unreleased.Backward compatibility
:on_stalearg is optionalstale-while-revalidateis not present.