Circuit Breaker
This example demonstrates how to implement the circuit breaker pattern as custom inbound and outbound policies in Zuplo. It proxies a real todo API at https://todo.zuplo.io and includes a failure simulator so you can see the circuit breaker in action.
This pattern is useful for:
- Backend protection: Automatically stop forwarding traffic when a downstream service is failing
- Fast failure: Return immediate 503 responses instead of waiting for a broken backend to time out
- Self-healing: Automatically probe the backend after a cooldown period and restore traffic when it recovers
Prerequisites
- A Zuplo account. You can sign up for free.
Deploy this example to Zuplo
Click the Deploy to Zuplo button anywhere on this page to create a new project in your Zuplo account with this example pre-configured. No additional setup is required.
How It Works
Two custom policies wrap every request:
Circuit breaker inbound (circuit-breaker-inbound.ts): Checks the circuit state before each request. If the circuit is open, it immediately returns a 503 response. If the cooldown period has elapsed, it transitions to half-open and allows the request through.
Circuit breaker outbound (circuit-breaker-outbound.ts): Inspects the response after each request. On failure, it increments the failure counter and opens the circuit when the threshold is reached. On success during half-open state, it closes the circuit.
Both policies share state through ZoneCache, which provides low-latency access to shared data within a deployment zone.
The included todo-handler.ts proxies requests to https://todo.zuplo.io and accepts an x-simulate-failure: true header to return a 500 instead of proxying, so you can test the circuit breaker without a real outage.
Request Flow
- Request arrives at the gateway
- Inbound policy checks circuit state in ZoneCache
closed→ allow throughopen(cooldown active) → return 503 immediatelyopen(cooldown expired) → transition tohalf-open, allow through
- Handler proxies to
https://todo.zuplo.io(or simulates failure) - Outbound policy inspects the response
- Success +
half-open→ close circuit, reset counter - Failure → increment counter; open circuit if threshold reached
- Success +
Project Structure
Key files:
modules/circuit-breaker-inbound.ts: Reads circuit state from ZoneCache. Blocks requests when open; transitions to half-open when cooldown expires.modules/circuit-breaker-outbound.ts: Writes circuit state to ZoneCache. Increments failure count on errors; resets on successful half-open probe.config/policies.json: ConfiguresfailureThreshold,cooldownSeconds, andbackendIdfor each circuit breaker policy.
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /todos | Get all todo items |
POST | /todos | Create a new todo |
PUT | /todos/{id} | Update a todo by ID |
DELETE | /todos/{id} | Delete a todo by ID |
All endpoints are protected by the circuit breaker.
Testing the Circuit Breaker
Replace YOUR_GATEWAY_URL with your deployed gateway’s URL.
1. Confirm requests flow normally
You should get back a list of todos from the real backend.
2. Trip the circuit
You’ll see five 500 responses. After the 5th, the circuit opens.
3. Confirm the circuit is open
No failure header this time — you get a 503 back instantly because the circuit is blocking all traffic to the backend.
4. Wait for recovery
The circuit transitions to half-open, lets this request through to the real backend, it succeeds, and the circuit closes. Subsequent requests flow normally again.
Configuration
Both circuit breaker policies accept the same options (configured in config/policies.json):
| Option | Type | Description |
|---|---|---|
failureThreshold | number | Failures before the circuit opens (default: 5) |
cooldownSeconds | number | Seconds to wait before half-open test (default: 30) |
backendId | string | Identifier for the protected backend |
stateTtlSeconds | number | Cache TTL for circuit state (default: 300) |
The backendId field lets you use different circuit breakers for different backends on different routes. Each backend gets its own independent failure tracking and circuit state.
Extending This Example
- Per-route thresholds: Configure a payment API with a threshold of 3 and a search API with a threshold of 10
- Failure detection by status code: Modify the outbound policy to only count 5xx errors, ignoring 4xx client errors
- Response time tracking: Open the circuit when response times exceed a threshold, not just on error codes
- Gradual recovery: In half-open state, allow a configurable number of test requests before fully closing the circuit
- Production handler: Replace
todo-handler.tswithurlForwardHandlerto proxy a real backend
Troubleshooting
- Deployed the example to Zuplo
- Replaced
YOUR_GATEWAY_URLwith your actual gateway URL in curl commands
Common errors:
| Error | Cause | Fix |
|---|---|---|
503 Service Unavailable immediately | Circuit is open | Wait for cooldownSeconds (default 30s) to elapse |
500 responses during testing | Expected — used to trip the circuit | Send 5 requests with x-simulate-failure: true header |
| Requests not failing after threshold | backendId mismatch between policies | Verify both policies use the same backendId in policies.json |