Stale cache response without background revalidation in HttpClient Cache plugin
0 reputation · 07 Aug 2020, 00:33 UTC
0 reputation · 07 Aug 2020, 00:33 UTC
The Ktor HttpClient Cache plugin manages response persistence based on standard Cache-Control headers. However, there is uncertainty regarding the implementation of RFC 7234 extensions, specifically stale-while-revalidate.
When a cached response exceeds its max-age but falls within a stale-while-revalidate window, the expected behavior is for the client to serve the stale content immediately while triggering an asynchronous background request to refresh the cache. In Ktor 2.x and 3.x, it appears the default plugin may serve stale entries without initiating this automatic background refresh.
This creates a gap in operational behavior where the client relies on manual conditional requests (e.g., If-None-Match) to ensure freshness, rather than leveraging the automated revalidation logic defined in the server's cache headers.
stale-while-revalidate directive for background refreshing?CacheStorage to implement asynchronous revalidation?34775 reputation · 07 Aug 2020, 10:00 UTC
The Ktor HttpClient Cache plugin does not natively support the stale-while-revalidate directive for automatic background refreshing. In Ktor 2.x and 3.x, the plugin follows a synchronous revalidation flow: if a cached response is stale (exceeds max-age), the client performs a conditional request using If-None-Match or If-Modified-Since before returning the response to the application.
While the plugin respects basic RFC 7234 expiration logic, it lacks the asynchronous dispatcher required to serve a stale response immediately while simultaneously triggering a network request to update the cache in the background. Consequently, the stale-while-revalidate header is effectively ignored by the default plugin implementation.
Because the HttpCache plugin is designed around a request-response pipeline, implementing background revalidation requires moving the refresh logic outside the primary request flow. You can achieve this by implementing a custom CacheStorage or wrapping the client.
To implement this behavior, follow these steps:
CacheStorage implementation that intercepts store and find calls.find returns a response that is stale but within the stale-while-revalidate window, return the cached response immediately to the caller.CoroutineScope) to perform a fresh httpClient.get() for that specific URI.Mutex or a map of active refreshes to ensure that multiple simultaneous requests for the same stale resource do not trigger redundant background network calls.To verify if your implementation (or a specific Ktor version) is performing background revalidation, use a network proxy (e.g., Charles or Fiddler):
Diagnostic Detail Needed: Are you using a custom CacheStorage implementation, or the default in-memory storage? The approach to intercepting the stale window differs depending on where the storage logic resides.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.