Refresh and Stale Reads
TTL says when a value expires. Refresh options say what the cache may do around expiry.
Use refresh behavior only when stale fallback is acceptable for the product path. It should be visible in code review.
let cache = HydraCache::local().build();
cache
.put(
"profile:42",
Profile {
id: 42,
display_name: "Ada".to_owned(),
},
CacheOptions::new().ttl(Duration::from_millis(10)),
)
.await?;
tokio::time::sleep(Duration::from_millis(20)).await;
let value = cache
.get_or_load_with_refresh(
"profile:42",
CacheOptions::new().ttl(Duration::from_secs(60)),
RefreshOptions::new().stale_while_revalidate(Duration::from_secs(5)),
|| async {
Ok::<_, LoadError>(Profile {
id: 42,
display_name: "Grace".to_owned(),
})
},
)
.await?;
assert_eq!(value.display_name, "Ada");
stale_while_revalidate lets the cache return a recently expired value while a background refresh runs. Once the stale window expires, callers return to foreground loading.
Related choices:
refresh_aheadrefreshes a value before expiry while still serving the fresh cached value;stale_while_revalidateserves an expired value inside a bounded window and refreshes in the background;stale_on_loader_errorcan return an expired value when the refresh loader fails.
Use diagnostics to confirm which path is happening in practice.