Reading fromTech Explained Simply
Volume 3 · Chapter 10ch 3.10 · 0/10 · lesson 5
Designing for Failure: Detection, Containment, Recovery, and Proof
📑 On this page
- A concrete example: database outage
- Define critical outcomes
- Service objectives
- Map dependencies
- Failure modes
- Timeouts
- Retries
- Idempotency
- Circuit breakers
- Bulkheads
- Load shedding
- Graceful degradation
- Redundancy
- Data durability
- Recovery
- Data reconciliation
- Observability
- Chaos and recovery testing
- Incident response
- Verification
- Maintain a failure-mode table
- Knowledge check
- The one idea to remember
Reliable systems are not built by assuming components never fail.
Designing for failure means choosing how the system detects, contains, communicates, recovers from, and verifies each important failure mode.
The design should preserve the most important user and safety outcomes under realistic loss.
A concrete example: database outage
During a database outage, decide:
- which reads can use cached data,
- which writes must stop,
- which writes can queue safely,
- how users see status,
- how retries are limited,
- and how queued work reconciles after recovery.
“Retry until it works” can turn one outage into duplicate actions and overload.
Define critical outcomes
Identify what must continue:
- safety,
- authentication,
- payment integrity,
- emergency communication,
- data preservation,
- or read-only access.
Not every feature needs the same availability. Priorities guide fallback and recovery order.
Service objectives
Set measurable objectives for:
- availability,
- latency,
- correctness,
- freshness,
- durability,
- and recovery.
An error budget makes reliability tradeoffs explicit. A system can be technically online while returning stale or incorrect results.
Map dependencies
List:
- services,
- databases,
- caches,
- identity,
- DNS,
- network,
- vendors,
- queues,
- configuration,
- secrets,
- and human operation.
Include hidden control-plane and deployment dependencies needed for recovery.
Failure modes
For each dependency ask:
- unavailable,
- slow,
- returning errors,
- returning wrong data,
- stale,
- overloaded,
- partially reachable,
- or compromised.
Incorrect success is often more dangerous than a visible failure.
Timeouts
Every remote call needs a deadline shorter than the overall user deadline.
Without timeouts, threads and connections accumulate while waiting. Set values from measured latency and consequence, not one global default.
Propagate remaining deadlines downstream.
Retries
Retry only transient failures likely to improve.
Use:
- bounded attempts,
- exponential backoff,
- jitter,
- deadlines,
- and idempotency.
Retries multiply load. A three-layer stack each retrying three times can create many requests from one action.
Idempotency
An idempotent operation can be repeated without creating additional effect.
Use request IDs or idempotency keys for payment, orders, messages, and jobs. Store the outcome so a retry receives the same result.
Reconciliation is needed when the first attempt's outcome is unknown.
Circuit breakers
A circuit breaker stops calling a failing dependency temporarily.
It protects resources and gives recovery time. The system can fail fast or use a fallback, then probe cautiously.
Tune it to avoid constant open-close oscillation.
Bulkheads
Bulkheads isolate resources so one failure does not consume everything.
Separate:
- connection pools,
- queues,
- worker groups,
- tenants,
- regions,
- and critical traffic.
Isolation can preserve checkout when analytics is overloaded.
Load shedding
When capacity is insufficient, reject or defer lower-priority work before the entire system collapses.
Use admission control, quotas, queue limits, and priority. Return clear retry guidance and avoid dropping accepted consequential work silently.
Graceful degradation
Provide reduced but useful service:
- cached catalogue,
- read-only mode,
- simpler recommendations,
- delayed analytics,
- or manual workflow.
Fallback must be tested and must preserve security and correctness. An insecure emergency mode is not graceful.
Redundancy
Replicas, regions, networks, and providers can reduce single points of failure.
Redundancy helps only when failures are independent and failover works. Shared credentials, configuration, software defects, or control planes create correlated failure.
Test actual isolation.
Data durability
Use replication and backups for different purposes.
Replication supports availability but can replicate deletion or corruption. Backups provide historical recovery if they are protected, retained, and restorable.
Define recovery point and recovery time objectives.
Recovery
Runbooks should state:
- trigger,
- owner,
- communication,
- failover,
- restore source,
- dependency order,
- validation,
- and return to normal.
Recovery must restore a trustworthy system, not merely start processes.
Data reconciliation
After partial failure, records may be duplicated, missing, delayed, or conflicting.
Use event IDs, versions, ledgers, and reports to reconcile. Know which source is authoritative.
Do not hide inconsistency through manual database edits without audit.
Observability
Detect failure through:
- user outcomes,
- service-level indicators,
- dependency health,
- queue depth,
- error type,
- data freshness,
- and synthetic checks.
Alert on actionable symptoms and attach runbooks. Component CPU alone does not reveal user harm.
Chaos and recovery testing
Inject controlled failures:
- terminate instances,
- delay dependencies,
- block network paths,
- expire credentials,
- corrupt test data,
- and restore backups.
Begin in safe environments and expand carefully. The purpose is to test assumptions, not create theatre.
Incident response
During incidents:
- establish command,
- protect people and data,
- communicate,
- mitigate,
- preserve evidence,
- and track decisions.
Afterward, identify system and organizational contributors without reducing the explanation to one person's mistake.
Verification
Recovery is complete only after checking:
- correctness,
- backlog,
- data integrity,
- security controls,
- monitoring,
- customer impact,
- and recurrence risk.
Watch the system after restoration because queued load can trigger a second failure.
Maintain a failure-mode table
For each critical dependency, keep a concise table with:
- failure mode,
- user effect,
- detection signal,
- timeout,
- retry policy,
- fallback,
- containment boundary,
- recovery owner,
- and verification step.
Review the table after incidents and architecture changes. It makes vague resilience claims testable and exposes dependencies that have detection but no recovery, or backups but no restoration owner.
Prioritize exercises using consequence and uncertainty. A rare catastrophic mode with an untested recovery may deserve attention before a frequent harmless error.
Knowledge check
- Why should failure modes include wrong or stale success?
- How can layered retries amplify an outage?
- What do bulkheads protect?
- Why are replication and backups different?
- What evidence proves recovery is complete?
The one idea to remember
Reliability comes from deciding what happens when dependencies are slow, wrong, unavailable, overloaded, or compromised. Use deadlines, bounded retries, idempotency, isolation, degradation, protected recovery, observability, exercises, and verification rather than hope.