TTL jitter and explicit stale windows
Spread expiration work without silently extending the maximum freshness contract.
On this page
The question for today
What you’ll understand
- Separate freshness eligibility, retained storage, and stale serving.
- Choose a jitter interval that preserves a stated maximum TTL.
- Calculate combined fresh and permitted-stale age bounds under explicit assumptions.
A thousand entries populated together can expire together and send a synchronized wave of work to the origin. TTL jitter spreads that work, but choosing the interval also changes the freshness contract. Expiration, physical deletion, and permission to serve stale data are separate mechanisms. Specify which age is bounded, which clock starts it, and what source freshness is assumed before claiming that a particular TTL limits staleness.
Age eligibility is not physical deletion
A cache can stop returning an expired entry before background cleanup reclaims its storage. Conversely, retaining stale bytes for revalidation does not make them eligible for an ordinary fresh hit. Use an absolute age or expiry rule appropriate to the product rather than extending freshness on every access by accident. A sliding inactivity timeout can keep a hot value resident indefinitely and therefore does not impose the same source-age bound as an absolute freshness lifetime.
A TTL measured from fill time bounds time since that fill only. If the origin read already came from a stale replica, total source age includes that prior lag. Network and clock uncertainty may matter for strict real-time promises. Permission or deletion changes can require active invalidation or a stronger source check rather than waiting for a general content TTL. State these cases separately instead of advertising one freshness number for every kind of data.
Stale serving spends an additional budget
A stale-while-revalidate policy can let an eligible request reuse an old response while a refresh proceeds, but must define the maximum additional window and the outcome when refresh fails or never starts. HTTP extensions have precise conditions; application caches need equally clear rules. Stale-if-error is another permission with a different trigger. Neither should quietly replace a requirement to check current authorization or to honor an explicit prohibition on stale reuse.
Adding positive jitter to a nominal TTL increases its maximum unless the nominal value was already budgeted below the limit. Adding a stale window increases the possible serving age further. Repeatedly resetting the original fill timestamp during failed refresh attempts can make an apparently bounded policy unbounded. Preserve trustworthy age metadata and validate the final serving decision against it. Track stale responses separately from fresh hits so an improved hit ratio cannot hide an expanded freshness compromise.
Randomization smooths expectation, not every burst
Independent jitter reduces synchronized expiry in expectation, but random clusters and correlated fills remain possible. A large deployment may seed generators badly or use coarse timer resolution, accidentally aligning expirations again. Refresh cost can vary by key, so even an equal count per second may produce uneven origin load. Combine jitter with coalescing, bounded concurrency, and a capacity-aware fallback rather than relying on randomness as the sole overload protection.
The probability lab is a limited independent-expiry-bin illustration. If TTLs are uniform over a fifteen-second interval, one chosen one-second bin has probability 1/15, which the control cannot represent exactly. Instead Reset and set both p=0.2, n=20 for five equal bins; predict four entries in one selected bin on average, then inspect the exact distribution. This fixed binomial model does not schedule TTLs, measure age, or serve stale data. Play highlights possible counts, not sampled expiration events.
Work it through
Preserve a sixty-second maximum
A content cache permits at most 60 seconds of fresh lifetime after a trustworthy fill, with independent subtractive jitter up to 15 seconds. It separately permits 10 seconds of stale serving under its stated refresh policy.
Chosen fresh TTLs lie between 45 and 60 seconds. With 1,000 simultaneous fills uniformly spread across this fifteen-second interval, expected expirations in an interior one-second bin are 1,000/15≈66.67, not an exact per-second count.
The maximum age since fill allowed by the fresh-plus-stale policy is 60+10=70 seconds, assuming the hard windows are enforced and refresh failures do not reset the fill age.
If the source was already five seconds stale at fill, the resulting source-age bound becomes 75 seconds. Do not label the policy as a universal sixty-second source-freshness guarantee.
Subtractive jitter preserves a fresh-lifetime maximum while stale permissions and preexisting source lag consume additional age budget.
The living notebook
Explore the model
Interactive lab · probability
Expiry bins have variability
Reset and set p=0.2, n=20; predict mean 4 entries in one of five equal-probability bins. This exact iid binomial model is not a TTL scheduler or stale-serving simulation, and it cannot express 1/15 exactly with its 0.01 probability step.
- Mean · np
- 5
- Variance · np(1−p)
- 2.5
- Total probability
- 1
These are exact binomial probabilities for independent trials with one fixed success probability. Playback tours the distribution; it does not resample outcomes. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forJitter smooths expected expiry work while actual bins can still cluster.
Pause & reason
Check your understanding
Your turn
Try it yourself
A fill contains data already four seconds old. Fresh lifetime is at most 30 seconds and an explicitly permitted stale window is eight seconds. Find the source-age bound under the stated additive model and name one invalidating implementation error.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Include source age before fill and do not reset its age during failed refreshes.
Compare with the solution
The bound is 4+30+8=42 seconds under enforced hard windows and trustworthy age metadata. Resetting the fill timestamp after a failed refresh would invalidate this calculation by disguising old data as newer. Unbounded source replica lag would also remove the initial four-second assumption and require a different freshness contract.
Keep the idea
Take it with you
- Freshness, physical cleanup, and stale permissions are separate.
- Subtractive jitter can preserve a maximum TTL; additive jitter can extend it.
- Age bounds must include source lag and prevent silent resets.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.