Safe degradation and fallbacks
Design cheaper useful responses with explicit freshness, authorization, quality, and recovery boundaries instead of hiding errors behind success codes.
On this page
The question for today
What you’ll understand
- Choose which semantics may degrade and which invariants must remain intact.
- Calculate fallback resource demand and cache-age eligibility.
- Design hysteresis, observability, and recovery tests for a fallback path.
A degraded response is useful only if it remains inside a deliberately defined contract. A product can omit a recommendation panel or serve an older public summary while preserving its central operation. It cannot silently bypass authorization or invent a successful payment because a dependency is slow. Fallbacks trade quality, freshness, or optional capability for bounded resource cost. They need their own capacity, correctness, and recovery evidence because the fallback often receives its largest workload precisely when the normal system is unhealthy.
State the invariant before choosing the shortcut
Separate the core operation from optional enrichment. Name which outputs may be omitted, approximated, delayed, or served from a cache, and make the changed behavior understandable to the caller where it matters. Define freshness and quality limits in the same way normal success is defined. A response that returns quickly with misleading content is not reliable merely because its HTTP status is successful. For AI systems, a smaller model or reduced retrieval set can change quality and safety behavior, so compare it using representative evaluations before calling it an acceptable degradation.
Authorization, privacy boundaries, and durable state invariants need explicit preservation. A cached protected response may require rechecking access or using a design whose invalidation and authorization scope are proven suitable. Revoked access should not silently become valid because the permission service is unavailable. Some operations should fail closed rather than fall back. Distinguish an eligible stale public result from an unsafe stale decision about ownership, account balance, or permissions. The fallback contract must name these exclusions instead of relying on a broad instruction to use the cache.
Provision the fallback for correlated demand
A fallback that works for one failed request can collapse when every caller uses it. Estimate total fallback demand under the triggering outage, including retries, cache misses, and any shared backend. Avoid a fallback that calls the same broken dependency through a different path. A local static response may be cheap but less useful; a remote secondary model may be useful but capacity constrained. Measure resource cost for both paths and cap admission so the fallback preserves a useful subset of work rather than causing another cascade.
Treat cold fallback state as a first-class test case. Data, credentials, compiled artifacts, and cache entries can expire when the path is rarely used. Exercise it under the intended outage workload and verify that essential dependencies remain reachable. A circuit breaker can stop repeated calls to an unhealthy service, but it needs bounded probes and a recovery policy. If all clients probe simultaneously, the attempted recovery can recreate overload. Use measured thresholds, controlled probes, and hysteresis rather than switching the entire population after one successful check.
Make degradation visible and reversible
Label fallback outcomes in telemetry separately from ordinary success and outright failure. Track eligible volume, actual fallback use, quality or freshness violations, cost, and user-visible completion. A global availability percentage can otherwise improve while product utility quietly worsens. Define when degraded outcomes count as good for each objective before activation. Preserve a way to disable a faulty fallback independently of the normal path; a stale cache or alternative model can have its own correctness incident while the main dependency is also unhealthy.
Recovery must restore normal behavior gradually and verify that fallback work and caches do not leave persistent effects. Test flapping dependency health, partial recovery, expired cache entries, and a failed fallback. The queue lab shows fluid backlog as arrival and service rates diverge, with a separately assumed M/M/1 mean residence readout. It does not know response quality, access rules, or cache freshness. Use it to illustrate the capacity benefit of cheaper work, then explain why those semantic constraints must be tested outside the model.
Work it through
A cheaper public-summary fallback
A fictional public-summary endpoint receives 1,000 operations/s. Normal work costs 0.010 CPU-seconds/operation; an already validated cached fallback costs 0.002. All operations in this workload are eligible for fallback, and during overload 60% use it. Available budget is six CPU-seconds/s. A cached result was generated 70 seconds ago and its maximum allowed age is 90 seconds.
Weighted CPU cost is 0.4 × 0.010 + 0.6 × 0.002 = 0.0052 CPU-seconds per operation.
Demand is 1,000 × 0.0052 = 5.2 CPU-seconds/s, leaving 0.8 CPU-seconds/s nominal budget under the stated measured-cost assumptions.
The cached value's 70-second age is within the 90-second limit, leaving 20 seconds of age eligibility. This does not separately prove invalidation or authorization correctness.
The fallback reduces modeled CPU demand from ten to 5.2 CPU-seconds/s while meeting the stated age check. Useful response quality and other bottlenecks remain independently validated requirements.
The living notebook
Explore the model
Interactive lab · queue
Cheaper work can create recovery headroom
Compare λ and μ as a simple illustration of demand and service headroom. Playback evolves fluid backlog max(0, 4 + (λ − μ)t); the separate M/M/1 mean readout does not evaluate response quality or fallback semantics.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. 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 forCapacity recovery supports graceful degradation only when freshness, quality, and access invariants remain satisfied.
Pause & reason
Check your understanding
Your turn
Try it yourself
A service receives 500 operations/s. Normal work costs 0.020 CPU-seconds each, fallback costs 0.004, and the CPU budget is six CPU-seconds/s. Under this constant-cost model, what minimum fallback fraction meets the budget? Name a reason the resulting fraction may still be unacceptable.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Require 500 × ((1 − f) × 0.020 + f × 0.004) ≤ 6 and solve for f.
Compare with the solution
Demand is 10 − 8f CPU-seconds/s, so 10 − 8f ≤ 6 gives f ≥ 0.5. At least 50% fallback meets this average CPU constraint. It may still violate response-quality, freshness, authorization, or another resource limit, and real costs can change under correlated outage demand. Capacity arithmetic alone cannot authorize the degradation policy.
Keep the idea
Take it with you
- A fallback must preserve named invariants while relaxing an explicit part of the contract.
- Test fallback capacity at correlated outage demand and with cold state.
- Observe degraded utility separately and control the return to normal behavior.
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.