Add `max_stale` parameter to `refresh_mode="background"` for configurable stale grace window · Issue #17009 · streamlit/streamlit · GitHub
Skip to content

Add max_stale parameter to refresh_mode="background" for configurable stale grace window #17009

Open

Description

@sfc-gh-lwilby-1

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_stale parameter: Explicitly configure the stale grace window (default: equal to ttl), e.g. ttl="1h", max_stale="12h" to serve stale data across an overnight idle gap without blocking the first morning user

Additional Context

Activity

  1. added
    type:enhancementRequests for feature enhancements or new features
    feature:cacheRelated to `st.cache_data` and `st.cache_resource`
    on Sep 17, 2026
  2. github-actions commented on Sep 17, 2026

    @github-actions
    Contributor

    To help Streamlit prioritize this feature, react with a 👍 (thumbs up emoji) to the initial post.

    Your vote helps us identify which enhancements matter most to our users.

    Views

  3. added
    ai-reviewIf applied to PR or issue will run AI review workflow
    on Sep 17, 2026
  4. lukasmasuch commented on Sep 17, 2026

    @lukasmasuch
    Collaborator

    Related aspect: you can configure the stale period via runner.cacheBackgroundRefreshTTLMultiplier across the entire app, but not per cache function.

  5. removed
    ai-reviewIf applied to PR or issue will run AI review workflow
    on Sep 17, 2026
  6. github-actions commented on Sep 17, 2026

    @github-actions
    Contributor

    This is an enhancement request to add a per-function max_stale parameter on st.cache_data / st.cache_resource so refresh_mode="background" can keep serving stale data longer than the current 1 × ttl grace window (hard expiry at 2 × ttl by default). The goal is to refresh often (ttl="2m") without blocking the first user after an overnight idle gap (max_stale="12h"), especially on scale-to-zero hosts where cron/pre-warm is impractical.

    This is already documented as future work in the background refresh product spec. Today the bound is process-wide only: runner.cacheBackgroundRefreshTTLMultiplier (default 2.0, shipped in #16599). Raising that option can cover a single long-idle cache, but it also lengthens the stale window for every other background cache in the process.

    Related Issues

    • #11050 — Origin of this request. Background refresh and lifespan cache warming landed there; @itsToggle then asked to decouple the 2 × ttl hard bound from the freshness TTL.
    • #8645 — Original stale-while-revalidate cache refresh request, implemented as refresh_mode="background". This issue extends that design with a per-function stale limit.
    • #6687 — Open request for background/cron-style execution. A scheduled refresher is an always-on alternative to max_stale for the “first user of the day” problem.

    This is an automated triage comment using cursor-grok-4.6-xhigh. Please verify the suggested labels and related issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature:cacheRelated to `st.cache_data` and `st.cache_resource`type:enhancementRequests for feature enhancements or new features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions