@@ -60,6 +60,9 @@ class HttpCache < Faraday::Middleware
6060 # The response was cached and can still be used.
6161 :fresh ,
6262
63+ # The response was stale but served while revalidating asynchronously.
64+ :stale ,
65+
6366 # The response was cached and the server has validated it with a 304 response.
6467 :valid ,
6568
@@ -84,6 +87,8 @@ class HttpCache < Faraday::Middleware
8487 # :shared_cache - A flag to mark the middleware as a shared cache or not.
8588 # :instrumenter - An instrumentation object that should respond to 'instrument'.
8689 # :instrument_name - The String name of the instrument being reported on (optional).
90+ # :on_stale - A Proc/lambda called with request:, env:, cached_response: when
91+ # a stale response is served within stale-while-revalidate window.
8792 # :logger - A logger object.
8893 # :max_entries - The maximum number of entries to store per cache key. This option is only
8994 # used when using the +ByUrl+ cache strategy.
@@ -103,14 +108,15 @@ class HttpCache < Faraday::Middleware
103108 # # Initialize the middleware with a MemoryStore and logger
104109 # store = ActiveSupport::Cache.lookup_store
105110 # Faraday::HttpCache.new(app, store: store, logger: my_logger)
106- def initialize ( app , options = { } )
111+ def initialize ( app , options = { } , & block )
107112 super ( app )
108113
109114 options = options . dup
110115 @logger = options [ :logger ]
111116 @shared_cache = options . delete ( :shared_cache ) { true }
112117 @instrumenter = options . delete ( :instrumenter )
113118 @instrument_name = options . delete ( :instrument_name ) { EVENT_NAME }
119+ @on_stale = options . delete ( :on_stale ) || block
114120
115121 strategy = options . delete ( :strategy ) { Strategies ::ByUrl }
116122
@@ -194,6 +200,10 @@ def process(env)
194200 if entry . fresh? && !@request . no_cache?
195201 response = entry . to_response ( env )
196202 trace :fresh
203+ elsif entry . stale_while_revalidate? && !@request . no_cache?
204+ response = entry . to_response ( env )
205+ trace :stale
206+ on_stale ( env , entry )
197207 else
198208 trace :must_revalidate
199209 response = validate ( entry , env )
@@ -312,6 +322,14 @@ def create_request(env)
312322 Request . from_env ( env )
313323 end
314324
325+ def on_stale ( env , cached_response )
326+ return unless @on_stale
327+
328+ @on_stale . call ( request : @request , env : env , cached_response : cached_response )
329+ rescue StandardError => e
330+ @logger &.warn ( "HTTP Cache: on_stale callback failed: #{ e . class } : #{ e . message } " )
331+ end
332+
315333 # Internal: Logs the trace info about the incoming request
316334 # and how the middleware handled it.
317335 # This method does nothing if theresn't a logger present.
0 commit comments