Add `max_stale` parameter to `refresh_mode="background"` for configurable stale grace window
Checklist
- I have searched the existing issues for similar feature requests.
- I added a descriptive title and summary to this issue.
Summary
When using refresh_mode="background" on st.cache_data / st.cache_resource, the stale grace window is fixed at 1×TTL (hard expiry at 2×TTL). This means an app idle overnight (longer than 2×TTL) has its cache evicted and the first morning user blocks on a cold miss.
A max_stale parameter would let users configure the stale grace window independently from TTL:
@st.cache_data(ttl="2m", max_stale="12h", refresh_mode="background")
def load_data():
return expensive_query()
This separates two concerns: how often to refresh (ttl="2m") from how long stale data is acceptable (max_stale="12h"). Users who want frequent freshness checks but never want to block get exactly that.
Why?
From #11050 (comment by @itsToggle):
Is there any way that we can influence the "2 × ttl" background cache timeout? In my use case I want a short ttl so the values are updated often, but I never want my users to have to wait for a response. I would like to set the ttl to something like 2 minutes, but the oldest background cache that's allowed to be served can be much older than four minutes.
This is also the more practical solution for the "first user of the day" problem compared to cron scheduling, since it does not require an always-on server and works on scale-to-zero deployments.
How?
The background refresh spec already calls this out as future work:
max_staleparameter: Explicitly configure the stale grace window (default: equal tottl), e.g.ttl="1h", max_stale="12h"to serve stale data across an overnight idle gap without blocking the first morning user
Additional Context
Source: streamlit/streamlit