Day 10: Operational Hardening and Chaos Testing — End-to-End Resilience
Day 10: Operational Hardening and Chaos Testing — End-to-End Resilience
In Day 9, you built a REST Order API that guarantees exactly-once processing using idempotency keys and optimized downstream pressure with standard HTTP cache controls. Today, we step up to the system integration level.
You will integrate three core architectural components: the REST Order API, a GraphQL Gateway, and a gRPC Inventory Service. You will then simulate a high-throughput production environment (5,000 concurrent requests per second), deliberately inject latency into the downstream gRPC service, and watch the entire topology collapse in a cascading failure. Finally, you will design, implement, and tune a custom, zero-dependency circuit breaker inside the GraphQL Gateway to fail fast, preserve system stability, and return elegant fallbacks.
The Production Stakes: The Anatomy of a Cascading Failure
In October 2021, Roblox suffered a historic 73-hour platform outage. While the root cause lay in a low-level consul cluster saturation, the catastrophic duration of the outage was exacerbated by cascading failures: upstream services repeatedly retried failed downstream calls, creating a self-inflicted Distributed Denial of Service (DDoS) attack that prevented the infrastructure from recovering.
A similar classic failure mode occurs when downstream latency spikes. Consider a gateway with a fixed thread pool of 200 workers. Under normal operations, a downstream call to an inventory service takes 10 milliseconds. The gateway can easily handle 20,000 requests per second ($200 text{ threads} times (1000text{ms} / 10text{ms})$).
If a network switch misbehaves or a database lock contention occurs downstream, causing that 10ms call to stretch to 2,000ms, the math changes instantly. The gateway's maximum throughput for that dependency collapses to 100 requests per second. If clients continue to send traffic at a modest rate of 1,000 requests per second, the gateway's thread pool will be completely saturated in exactly 200 milliseconds.
Once saturated, every other endpoint hosted on that gateway—even those completely unrelated to inventory—will block and fail. This is a cascading failure.
To prevent this, we use a Circuit Breaker. Named after the electrical safety device that interrupts an overloaded circuit, the software circuit breaker wraps downstream calls. It monitors failure and latency rates. When they exceed a defined threshold, the breaker trips (opens), instantly routing all subsequent calls to a local fallback routine without making a network hop.
The Mechanism: The Circuit Breaker State Machine
The circuit breaker operates as a state machine with three distinct states:
Closed: Traffic flows normally to the downstream service. The breaker monitors the outcome of every call. If the failure rate or slow-call rate exceeds your threshold, the breaker trips to the Open state.
Open: All calls fail fast immediately. The downstream service is completely shielded from traffic, giving it space to recover. A cooldown timer starts. When it expires, the breaker transitions to Half-Open.
Half-Open: A limited trial of real traffic is allowed through. If these trial calls succeed, the breaker assumes the downstream service has recovered and resets to Closed. If even a single trial call fails, the breaker immediately returns to Open, resetting the cooldown timer.
Design Trade-offs: Fail-Fast vs. Degraded Functionality
Keep going with the full lesson
The rest of this lesson — plus its implementation guide, runnable scripts and source code — is included with the course or an All Access plan. Create a free account to start the free lessons in every course.
Already a member? Sign in