circuit-breaker

Circuit Breaker Pattern

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "circuit-breaker" with this command: npx skills add dadbodgeoff/drift/dadbodgeoff-drift-circuit-breaker

Circuit Breaker Pattern

Prevent cascade failures by failing fast when a service is unhealthy.

When to Use This Skill

  • Adding resilience to external API calls

  • Protecting against slow or failing downstream services

  • Implementing graceful degradation

  • Building fault-tolerant microservices

Core Concepts

A circuit breaker has three states:

  • CLOSED: Normal operation, requests pass through

  • OPEN: Service is failing, requests fail immediately

  • HALF_OPEN: Testing if service recovered

TypeScript Implementation

// circuit-breaker.ts type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

interface CircuitBreakerConfig { failureThreshold: number; // Failures before opening successThreshold: number; // Successes to close from half-open timeout: number; // Ms before trying half-open fallback?: () => Promise<any>; // Optional fallback }

class CircuitBreaker { private state: CircuitState = 'CLOSED'; private failures = 0; private successes = 0; private lastFailureTime = 0; private readonly config: CircuitBreakerConfig;

constructor(config: Partial<CircuitBreakerConfig> = {}) { this.config = { failureThreshold: 5, successThreshold: 2, timeout: 30000, ...config, }; }

async execute<T>(fn: () => Promise<T>): Promise<T> { if (this.state === 'OPEN') { if (Date.now() - this.lastFailureTime >= this.config.timeout) { this.state = 'HALF_OPEN'; } else { if (this.config.fallback) { return this.config.fallback(); } throw new CircuitOpenError('Circuit is OPEN'); } }

try {
  const result = await fn();
  this.onSuccess();
  return result;
} catch (error) {
  this.onFailure();
  throw error;
}

}

private onSuccess(): void { this.failures = 0; if (this.state === 'HALF_OPEN') { this.successes++; if (this.successes >= this.config.successThreshold) { this.state = 'CLOSED'; this.successes = 0; } } }

private onFailure(): void { this.failures++; this.lastFailureTime = Date.now(); if (this.failures >= this.config.failureThreshold) { this.state = 'OPEN'; } }

getState(): CircuitState { return this.state; } }

class CircuitOpenError extends Error { constructor(message: string) { super(message); this.name = 'CircuitOpenError'; } }

export { CircuitBreaker, CircuitBreakerConfig, CircuitOpenError };

Python Implementation

circuit_breaker.py

import time from enum import Enum from typing import Callable, TypeVar, Optional from functools import wraps

T = TypeVar('T')

class CircuitState(Enum): CLOSED = "closed" OPEN = "open" HALF_OPEN = "half_open"

class CircuitOpenError(Exception): pass

class CircuitBreaker: def init( self, failure_threshold: int = 5, success_threshold: int = 2, timeout: float = 30.0, fallback: Optional[Callable] = None, ): self.failure_threshold = failure_threshold self.success_threshold = success_threshold self.timeout = timeout self.fallback = fallback

    self._state = CircuitState.CLOSED
    self._failures = 0
    self._successes = 0
    self._last_failure_time = 0.0

@property
def state(self) -> CircuitState:
    return self._state

def __call__(self, fn: Callable[..., T]) -> Callable[..., T]:
    @wraps(fn)
    def wrapper(*args, **kwargs) -> T:
        return self.execute(lambda: fn(*args, **kwargs))
    return wrapper

def execute(self, fn: Callable[[], T]) -> T:
    if self._state == CircuitState.OPEN:
        if time.time() - self._last_failure_time >= self.timeout:
            self._state = CircuitState.HALF_OPEN
        else:
            if self.fallback:
                return self.fallback()
            raise CircuitOpenError("Circuit is OPEN")

    try:
        result = fn()
        self._on_success()
        return result
    except Exception as e:
        self._on_failure()
        raise

def _on_success(self) -> None:
    self._failures = 0
    if self._state == CircuitState.HALF_OPEN:
        self._successes += 1
        if self._successes >= self.success_threshold:
            self._state = CircuitState.CLOSED
            self._successes = 0

def _on_failure(self) -> None:
    self._failures += 1
    self._last_failure_time = time.time()
    if self._failures >= self.failure_threshold:
        self._state = CircuitState.OPEN

Usage Examples

TypeScript with API Client

const paymentCircuit = new CircuitBreaker({ failureThreshold: 3, timeout: 60000, fallback: async () => ({ status: 'pending', message: 'Payment service unavailable' }), });

async function processPayment(amount: number) { return paymentCircuit.execute(async () => { const response = await fetch('https://api.stripe.com/v1/charges', { method: 'POST', body: JSON.stringify({ amount }), }); if (!response.ok) throw new Error('Payment failed'); return response.json(); }); }

Python Decorator Style

circuit = CircuitBreaker(failure_threshold=3, timeout=60)

@circuit def call_external_api(endpoint: str) -> dict: response = requests.get(endpoint, timeout=5) response.raise_for_status() return response.json()

Integration with Observability

Add metrics to track circuit state:

// With Prometheus import { Gauge, Counter } from 'prom-client';

const circuitState = new Gauge({ name: 'circuit_breaker_state', help: 'Current circuit breaker state (0=closed, 1=open, 2=half-open)', labelNames: ['service'], });

const circuitTrips = new Counter({ name: 'circuit_breaker_trips_total', help: 'Total circuit breaker trips', labelNames: ['service'], });

Best Practices

  • Tune thresholds per service: Critical services need lower thresholds

  • Always provide fallbacks: Graceful degradation > hard failures

  • Monitor circuit state: Alert when circuits open frequently

  • Use separate circuits: One per external dependency

  • Consider bulkheads: Combine with connection pooling

Common Mistakes

  • Setting timeout too short (service never recovers)

  • Sharing circuits across unrelated services

  • Not handling CircuitOpenError in calling code

  • Forgetting to add observability

Related Patterns

  • Retry with exponential backoff

  • Bulkhead isolation

  • Timeout pattern

  • Fallback pattern

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

oauth-social-login

No summary provided by upstream source.

Repository SourceNeeds Review
General

sse-streaming

No summary provided by upstream source.

Repository SourceNeeds Review
General

multi-tenancy

No summary provided by upstream source.

Repository SourceNeeds Review
General

deduplication

No summary provided by upstream source.

Repository SourceNeeds Review