resilience-patterns
Production resilience patterns: Circuit Breaker (Closed/Open/Half-Open), Bulkhead isolation, Retry with exponential backoff + jitter, Timeout hierarchies, Fallback strategies, Graceful Degradation, and Health Check patterns for Kubernetes and beyond.
Best use case
resilience-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Production resilience patterns: Circuit Breaker (Closed/Open/Half-Open), Bulkhead isolation, Retry with exponential backoff + jitter, Timeout hierarchies, Fallback strategies, Graceful Degradation, and Health Check patterns for Kubernetes and beyond.
Teams using resilience-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/resilience-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How resilience-patterns Compares
| Feature / Agent | resilience-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Production resilience patterns: Circuit Breaker (Closed/Open/Half-Open), Bulkhead isolation, Retry with exponential backoff + jitter, Timeout hierarchies, Fallback strategies, Graceful Degradation, and Health Check patterns for Kubernetes and beyond.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Resilience Patterns Skill
External dependencies fail. Networks partition. Databases become slow. This skill covers the patterns that keep your service running when dependencies don't.
## When to Activate
- Designing a service that calls external APIs, databases, or queues
- Adding retry logic to an HTTP client
- Implementing circuit breakers for external calls
- Reviewing architecture for single points of failure
- Preparing for a resilience audit or chaos experiment
- Deciding which HTTP error codes should be retried vs. treated as permanent failures
- Isolating slow dependencies using bulkhead thread-pool or connection-pool partitioning
- Configuring Kubernetes liveness, readiness, and startup probes for a new service
---
## Circuit Breaker
The Circuit Breaker prevents cascading failures. When a dependency fails repeatedly, stop calling it and fail fast — don't queue up thousands of slow requests.
### States
```
CLOSED (normal)
├── Success → stay CLOSED
└── Failure count > threshold → OPEN
OPEN (failing fast)
├── All calls rejected immediately → return fallback
└── After recovery timeout → HALF-OPEN
HALF-OPEN (probing)
├── Next call succeeds → CLOSED
└── Next call fails → OPEN
```
### Implementation by Language
**Java — Resilience4j (recommended)**
```java
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // Open at 50% failure rate
.waitDurationInOpenState(Duration.ofSeconds(30))
.permittedNumberOfCallsInHalfOpenState(3)
.slidingWindowSize(10)
.build();
CircuitBreaker cb = CircuitBreaker.of("payment-service", config);
// Decorate your call
Supplier<String> decorated = CircuitBreaker.decorateSupplier(cb, () ->
paymentClient.charge(amount)
);
Try.ofSupplier(decorated)
.recover(CallNotPermittedException.class, ex -> "fallback-response");
```
**Node.js — opossum**
```javascript
import CircuitBreaker from 'opossum';
const options = {
timeout: 3000, // 3s timeout per call
errorThresholdPercentage: 50, // Open at 50% failures
resetTimeout: 30000, // Try again after 30s
};
const breaker = new CircuitBreaker(riskyOperation, options);
breaker.fallback(() => 'fallback response');
breaker.on('open', () => console.warn('Circuit OPEN'));
breaker.on('halfOpen', () => console.info('Circuit HALF-OPEN'));
await breaker.fire(args);
```
**Python — pybreaker**
```python
import pybreaker
db_breaker = pybreaker.CircuitBreaker(
fail_max=5, # Open after 5 consecutive failures
reset_timeout=30, # Reset after 30 seconds
)
@db_breaker
def query_database(sql):
return db.execute(sql)
```
**Go — go-circuit-breaker (sony/gobreaker)**
```go
import "github.com/sony/gobreaker"
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "payment-api",
MaxRequests: 3,
Interval: 10 * time.Second,
Timeout: 30 * time.Second,
ReadyToTrip: func(counts gobreaker.Counts) bool {
return counts.ConsecutiveFailures > 5
},
})
result, err := cb.Execute(func() (interface{}, error) {
return paymentClient.Charge(ctx, amount)
})
```
---
## Bulkhead Pattern
Isolate resources by concern. Prevent one slow dependency from exhausting all threads/connections.
### Thread Pool Isolation
```java
// Resilience4j Bulkhead — limit concurrent calls to payment service
BulkheadConfig config = BulkheadConfig.custom()
.maxConcurrentCalls(10) // Max 10 simultaneous calls
.maxWaitDuration(Duration.ofMillis(100)) // Fail fast if full
.build();
Bulkhead bulkhead = Bulkhead.of("payment-service", bulkhead config);
// Inventory service gets its own bulkhead — cannot starve payment
Bulkhead inventoryBulkhead = Bulkhead.of("inventory-service", ...);
```
### Connection Pool Isolation
```javascript
// Node.js — separate pg pools per use case
const readPool = new Pool({ max: 10, idleTimeoutMillis: 30000 });
const writePool = new Pool({ max: 5, idleTimeoutMillis: 30000 });
const analyticsPool = new Pool({ max: 2, idleTimeoutMillis: 60000 });
// Analytics queries cannot exhaust write connections
```
---
## Retry with Backoff
**Naive retry** (bad — amplifies load on failing service):
```
retry immediately → retry immediately → retry immediately
```
**Exponential Backoff + Jitter** (correct):
```
attempt 1 failed → wait ~1s
attempt 2 failed → wait ~2s
attempt 3 failed → wait ~4s (+/- jitter)
attempt 4 failed → give up
```
### Decorrelated Jitter (recommended — Cloudflare/AWS pattern)
```python
import random
import time
def retry_with_decorrelated_jitter(fn, max_retries=4, base=1, cap=60):
sleep = base
for attempt in range(max_retries):
try:
return fn()
except TransientError as e:
if attempt == max_retries - 1:
raise
sleep = min(cap, random.uniform(base, sleep * 3))
time.sleep(sleep)
```
```go
// Go — exponential backoff with jitter
func withRetry(ctx context.Context, fn func() error) error {
b := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
Multiplier: 2,
MaxInterval: 30 * time.Second,
MaxElapsedTime: 2 * time.Minute,
}
return backoff.Retry(fn, backoff.WithContext(b, ctx))
}
```
### What to Retry
| Error Type | Retry? | Why |
|------------|--------|-----|
| HTTP 429 Too Many Requests | Yes | With respect for `Retry-After` header |
| HTTP 500 Internal Server Error | Yes | Transient server error |
| HTTP 502/503/504 | Yes | Gateway/upstream issue |
| Network timeout | Yes | Transient |
| HTTP 400 Bad Request | **No** | Client bug — retrying won't help |
| HTTP 401/403 | **No** | Auth issue — retrying won't help |
| HTTP 404 Not Found | **No** | Resource missing |
**Idempotency:** Only retry operations that are safe to repeat. POST requests that create resources must be idempotent (use idempotency keys) before adding retry.
---
## Timeout Hierarchies
Every external call needs a timeout. Multiple layers, inner ones tighter:
```
User Request Deadline: 5000ms (Context deadline in Go)
└── Payment Service Call: 3000ms
└── Payment Provider API: 2000ms (HTTP client timeout)
├── Connect Timeout: 500ms
└── Read Timeout: 1500ms
```
### By Language
**Go — context-based deadlines (idiomatic)**
```go
// Outer: propagate context from HTTP request
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
resp, err := paymentClient.Charge(ctx, amount)
if errors.Is(err, context.DeadlineExceeded) {
// Return 504 to caller
}
```
**Java — HttpClient with timeout**
```java
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(500))
.build();
HttpRequest request = HttpRequest.newBuilder()
.timeout(Duration.ofSeconds(3))
.uri(URI.create(url))
.build();
```
**Python — httpx (preferred over requests for timeouts)**
```python
import httpx
async with httpx.AsyncClient() as client:
response = await client.get(
url,
timeout=httpx.Timeout(connect=0.5, read=2.0, write=1.0, pool=0.5)
)
```
---
## Fallback Strategies
When the dependency is unavailable, what do you return?
| Strategy | Example | Use When |
|----------|---------|----------|
| **Static default** | `{ "recommendations": [] }` | Empty is acceptable |
| **Cached value** | Last successful response from cache | Stale data is better than nothing |
| **Degraded mode** | Show prices without personalization | Core feature must continue |
| **Queue for later** | Write to local queue, process when recovered | Eventual consistency acceptable |
| **Fail fast + user message** | "Feature temporarily unavailable" | No meaningful fallback exists |
```javascript
// Node.js — Redis cache fallback pattern
async function getUserProfile(userId) {
try {
const profile = await profileService.get(userId);
await cache.set(`profile:${userId}`, profile, 'EX', 300);
return profile;
} catch (err) {
// Service unavailable — try cache
const cached = await cache.get(`profile:${userId}`);
if (cached) return { ...JSON.parse(cached), _stale: true };
// Cache miss — return minimal profile
return { userId, name: 'User', _degraded: true };
}
}
```
---
## Graceful Degradation
Emergency shutoff via feature flags:
```javascript
// Emergency: disable recommendation engine during incident
if (await featureFlags.isEnabled('recommendations', userId)) {
recommendations = await recommendationService.get(userId);
} else {
recommendations = await getTopSellers(); // always works, no ML
}
```
**Read-Only Mode** — when writes fail, serve reads:
```go
var readOnlyMode atomic.Bool
func handleWrite(w http.ResponseWriter, r *http.Request) {
if readOnlyMode.Load() {
http.Error(w, "Service in read-only mode", http.StatusServiceUnavailable)
return
}
// ... normal write logic
}
```
---
## Health Check Patterns (Kubernetes)
```yaml
livenessProbe: # Is the process healthy? Restart if fails.
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3 # Restart after 3 consecutive failures
readinessProbe: # Is the service ready for traffic? Remove from LB if fails.
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 2 # Remove from LB faster than we restart
startupProbe: # Give slow-starting apps time to initialize.
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30 # Allow 5 minutes (30 * 10s) for startup
periodSeconds: 10
```
**Health check implementation:**
```go
// /health/live — is the process running?
func livenessHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
// /health/ready — can we serve traffic?
func readinessHandler(w http.ResponseWriter, r *http.Request) {
if err := db.PingContext(r.Context()); err != nil {
http.Error(w, "db unhealthy", http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
}
```
---
## Anti-Patterns to Avoid
| Anti-Pattern | Problem | Fix |
|--------------|---------|-----|
| Retry without jitter | Thundering herd after outage | Add decorrelated jitter |
| Infinite retries | Never gives up, cascades | Set max retries + circuit breaker |
| Same timeout for all dependencies | DB needs different timeout than cache | Per-dependency timeouts |
| Circuit breaker on every error | Opens on expected errors (404, 400) | Only count transient errors |
| No fallback in circuit open state | Error instead of degraded response | Always define fallback |
| Health check queries database | DB slow → all pods removed from LB → thundering herd | Separate liveness (process) from readiness (deps) |
---
## Reference Skills
- `chaos-engineering` — testing that these patterns work
- `observability` — monitoring circuit breaker state and retry rates
- `load-testing` — validating behavior under loadRelated Skills
zero-trust-patterns
Zero-Trust security patterns — mTLS between microservices (Istio/SPIFFE), SPIRE workload identity, OPA/Envoy authorization, NetworkPolicy default-deny-all, short-lived credentials, service mesh security, and Kubernetes RBAC hardening.
webrtc-patterns
WebRTC patterns — peer connection setup, ICE/STUN/TURN configuration, signaling server design, SFU vs mesh topology, screen sharing, media track management, and reconnect/ICE restart handling.
webhook-patterns
Webhook patterns for receiving, verifying (HMAC), and idempotently processing third-party events. Covers Stripe, GitHub, and generic webhook patterns, delivery guarantees, retry handling, and testing.
wasm-patterns
WebAssembly patterns: wasm-pack, wasm-bindgen (JS↔Wasm interop), WASI, Component Model, wasm-opt, Rust-to-WASM compilation, JS integration (web workers, streaming instantiation), and production deployment (CDN, Content-Type headers).
ux-micro-patterns
UX micro-patterns for every product state: Empty States, Loading States (skeleton screens, spinners, optimistic UI), Error States, Success States, Confirmation Dialogs, Onboarding Flows, and Progressive Disclosure. These patterns apply to every feature — done wrong, they're the biggest source of user confusion.
typescript-patterns
TypeScript patterns — type system best practices, strict mode, utility types, generics, discriminated unions, error handling with Result types, and module organization. Core patterns for production TypeScript.
typescript-patterns-advanced
Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.
typescript-monorepo-patterns
TypeScript monorepo patterns with Turborepo + pnpm workspaces. Covers package structure, shared configs, task pipeline caching, build orchestration, and publishing strategy.
terraform-patterns
Infrastructure as Code with Terraform — project structure, remote state, modules, workspace strategy, AWS/GCP patterns, CI/CD integration, and security hardening. The standard for managing production infrastructure.
swiftui-patterns
SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
swift-patterns
Core Swift patterns — value vs reference types, protocols, generics, optionals, Result, error handling, Codable, and module organization. Foundation for all Swift development.
swift-patterns-advanced
Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.