skills/a6-recipe-circuit-breaker/SKILL.md
Recipe skill for implementing circuit breaker patterns using the a6 CLI. Covers the api-breaker plugin for automatic upstream circuit breaking, configuring unhealthy thresholds, healthy recovery, response code classification, and integration with health checks.
npx skillsauth add moonming/a6 a6-recipe-circuit-breakerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A circuit breaker prevents cascading failures by detecting unhealthy upstream services and temporarily stopping requests to them. When the upstream returns too many errors, the circuit "opens" and APISIX returns errors immediately without forwarding requests. After a cooldown period, it "half-opens" to test if the upstream has recovered.
APISIX implements this via the api-breaker plugin, which tracks response
status codes and manages circuit state automatically.
┌─────────┐
│ CLOSED │ ← Normal operation: requests flow through
│(healthy) │
└────┬─────┘
│ Error count exceeds threshold
▼
┌─────────┐
│ OPEN │ ← Breaker tripped: returns 502 immediately
│(tripped) │
└────┬─────┘
│ After cooldown period
▼
┌──────────┐
│HALF-OPEN │ ← Test: allows one request through
│ (testing) │
└─────┬────┘
│
┌───────┴───────┐
│ │
Success Failure
│ │
▼ ▼
CLOSED OPEN (longer cooldown)
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| break_response_code | integer | Yes | — | HTTP status code returned when circuit is open (e.g., 502, 503). |
| break_response_body | string | No | — | Response body returned when circuit is open. |
| break_response_headers | array[object] | No | — | Response headers when circuit is open. Format: [{"key": "name", "value": "val"}]. |
| unhealthy.http_statuses | array[integer] | No | [500] | HTTP status codes from upstream that count as unhealthy. |
| unhealthy.failures | integer | No | 3 | Number of consecutive unhealthy responses before opening the circuit. |
| healthy.http_statuses | array[integer] | No | [200] | HTTP status codes from upstream that count as healthy (for recovery). |
| healthy.successes | integer | No | 3 | Number of consecutive healthy responses to close the circuit. |
| max_breaker_sec | integer | No | 300 | Maximum circuit-open duration in seconds. Cooldown doubles each time but caps here. |
When the circuit opens:
max_breaker_sec (default 300s = 5 minutes)During cooldown, all requests get the break_response_code immediately.
a6 route create -f - <<'EOF'
{
"id": "protected-api",
"uri": "/api/*",
"plugins": {
"api-breaker": {
"break_response_code": 502,
"unhealthy": {
"http_statuses": [500, 502, 503],
"failures": 3
},
"healthy": {
"http_statuses": [200],
"successes": 3
},
"max_breaker_sec": 300
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
After 3 consecutive 500/502/503 responses, the circuit opens and returns 502 immediately. After cooldown, it tests with one request. If 3 consecutive 200s come back, the circuit closes and normal operation resumes.
a6 route create -f - <<'EOF'
{
"id": "api-with-error-body",
"uri": "/api/*",
"plugins": {
"api-breaker": {
"break_response_code": 503,
"break_response_body": "{\"error\": \"service temporarily unavailable\", \"retry_after\": 30}",
"break_response_headers": [
{"key": "Content-Type", "value": "application/json"},
{"key": "Retry-After", "value": "30"}
],
"unhealthy": {
"http_statuses": [500, 502, 503, 504],
"failures": 5
},
"healthy": {
"http_statuses": [200, 201, 204],
"successes": 2
},
"max_breaker_sec": 60
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
{
"plugins": {
"api-breaker": {
"break_response_code": 503,
"unhealthy": {
"http_statuses": [500, 502, 503],
"failures": 1
},
"healthy": {
"http_statuses": [200],
"successes": 1
},
"max_breaker_sec": 30
}
}
}
Trips on the very first 5xx error. Recovers after one successful response.
For production, combine the circuit breaker with upstream health checks. The circuit breaker handles per-route protection while health checks manage per-node health at the upstream level.
# Create upstream with health checks
a6 upstream create -f - <<'EOF'
{
"id": "monitored-backend",
"type": "roundrobin",
"nodes": {
"backend-1:8080": 1,
"backend-2:8080": 1
},
"checks": {
"active": {
"type": "http",
"http_path": "/health",
"healthy": {
"interval": 5,
"successes": 2
},
"unhealthy": {
"interval": 3,
"http_failures": 3
}
}
}
}
EOF
# Create route with circuit breaker
a6 route create -f - <<'EOF'
{
"id": "api",
"uri": "/api/*",
"plugins": {
"api-breaker": {
"break_response_code": 503,
"unhealthy": {
"http_statuses": [500, 502, 503],
"failures": 3
},
"healthy": {
"http_statuses": [200],
"successes": 3
}
}
},
"upstream_id": "monitored-backend"
}
EOF
version: "1"
routes:
- id: protected-api
uri: /api/*
plugins:
api-breaker:
break_response_code: 503
break_response_body: '{"error": "service unavailable"}'
break_response_headers:
- key: Content-Type
value: application/json
- key: Retry-After
value: "30"
unhealthy:
http_statuses: [500, 502, 503]
failures: 3
healthy:
http_statuses: [200]
successes: 3
max_breaker_sec: 300
upstream_id: backend
upstreams:
- id: backend
type: roundrobin
nodes:
"backend:8080": 1
| Symptom | Cause | Fix |
|---------|-------|-----|
| Circuit never opens | unhealthy.http_statuses doesn't include the error code | Add the actual error codes your upstream returns |
| Circuit stays open too long | max_breaker_sec too high | Lower max_breaker_sec for faster recovery |
| Circuit flaps open/closed | Threshold too low with intermittent errors | Increase unhealthy.failures threshold |
| 502 from APISIX (not circuit breaker) | Upstream truly unreachable (connection refused) | Connection errors also count toward unhealthy threshold |
| Recovery too slow | healthy.successes too high | Lower healthy.successes for faster recovery |
tools
Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and development workflow. Load this skill when working on a6 source code, adding new commands, writing tests, or modifying any a6 component.
tools
Recipe skill for implementing multi-tenant API gateway patterns using the a6 CLI. Covers tenant isolation via Consumer Groups, host/path/header-based routing, per-tenant rate limiting, context forwarding with proxy-rewrite, and declarative config sync workflows for multi-tenant management.
tools
Recipe skill for configuring mutual TLS (mTLS) using the a6 CLI. Covers SSL certificate management, upstream mTLS to backend services, client certificate verification, and end-to-end mTLS setup from client through APISIX to upstream.
tools
Recipe skill for configuring upstream health checks using the a6 CLI. Covers active health checks (HTTP probing), passive health checks (response analysis), combining both, configuring healthy/unhealthy thresholds, and monitoring upstream node status.