← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Circuit Breaker Pattern

architecture PHP 5.0+ Intermediate
debt(d9/e5/b5/t7)
d9 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production until users hit it' (d9). The detection_hints indicate automated detection is 'no' and tools listed (Blackfire, Datadog) are observability/profiling tools, not static analysis. The absence of a circuit breaker is invisible at code review, at lint time, and at test time — it only manifests when a downstream dependency degrades and cascading failures pile up in production under real traffic.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes wrapping external service calls with a circuit breaker library and adding fallback logic. This requires identifying every external call site, integrating a circuit breaker abstraction (e.g. a library or custom implementation), configuring thresholds, implementing half-open state probing, and adding monitoring/alerting for circuit state — spanning multiple files and components rather than a single-line swap.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The pattern applies to web, API, and queue-worker contexts wherever external dependencies exist. Once adopted, every future external integration must be evaluated for circuit breaker wrapping, threshold tuning, fallback strategy, and monitoring. It imposes an ongoing design and operational tax across many work streams without being fully architectural.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field explicitly states that developers commonly conflate circuit breakers with retry patterns, believing they solve the same problem. This is a serious trap: retries are intuitive (try again on failure) while circuit breakers invert that intuition (stop trying entirely). A developer familiar with retry logic will apply retries where a circuit breaker is needed, making the failure mode worse by hammering a failing dependency.

About DEBT scoring →

Also Known As

circuit breaker pattern fail fast circuit service circuit breaker

TL;DR

Wrapping calls to a flaky downstream service with a state machine that opens (stops calls) after threshold failures, preventing cascade failures.

Explanation

Named after an electrical circuit breaker, the pattern has three states: Closed (normal — calls pass through, failures are counted), Open (tripped — calls fail immediately without attempting the downstream call, returning a fallback), and Half-Open (trial — a probe request is allowed through after a timeout; if it succeeds, the circuit closes; if it fails, it reopens). This prevents a slow or failing downstream service from exhausting all threads/connections in the caller, turning a partial failure into a total outage. PHP implementations: Ganesha, php-circuit-breaker, or a custom Redis-backed state machine. Pair with the Bulkhead and Retry patterns for comprehensive resilience.

Diagram

stateDiagram-v2
    [*] --> Closed
    Closed --> Open: Failure threshold exceeded
    Open --> HalfOpen: Timeout elapsed
    HalfOpen --> Closed: Test request succeeds
    HalfOpen --> Open: Test request fails
    note right of Closed: Requests pass through
    note right of Open: Requests fail immediately
    note right of HalfOpen: One test request allowed
style Closed fill:#238636,color:#fff
style Open fill:#f85149,color:#fff
style HalfOpen fill:#d29922,color:#fff

Common Misconception

A circuit breaker and a retry pattern solve the same problem. Retries handle transient failures — worth retrying immediately. Circuit breakers handle sustained failures — the dependency is down, stop hammering it and fail fast until it recovers. Both are needed together.

Why It Matters

Without a circuit breaker, a slow or failing downstream service causes your threads to pile up waiting for timeouts — one dependency failure cascades into a full application outage. Circuit breakers fail fast when a service is unhealthy, shedding load and allowing recovery.

Common Mistakes

  • Setting the threshold too low — a single failed request opening the circuit causes unnecessary outages.
  • Not implementing a half-open state — the circuit must probe for recovery, not stay open indefinitely.
  • Wrapping every external call in a circuit breaker including fast, internal ones — overhead is not always worth it.
  • Not monitoring circuit state — an open circuit is a live incident that needs alerting.

Avoid When

  • Calling internal services or local resources where latency is negligible and failures are surfaced immediately.
  • Operations that must not be silently skipped — payments, critical writes — where the fallback is worse than waiting.
  • Low-traffic services where the circuit will never accumulate enough failures to trip.
  • When a retry with exponential backoff is sufficient and simpler.

When To Use

  • External HTTP API calls, third-party services, or any dependency that can be slow or unavailable.
  • Microservice architectures where one failing service must not cascade and bring down the entire system.
  • Any call where a fast failure and fallback is preferable to a slow queue of blocked requests.
  • Systems with SLA requirements where downstream failures must not exceed a time budget.

Code Examples

✗ Vulnerable
// No circuit breaker — repeated calls to a failing service:
function getUser(int $id): ?User {
    return Http::get("https://user-service/users/$id"); // Times out on every call
    // With circuit breaker: after N failures, return null immediately
    // and only retry after a cooldown period
}
✓ Fixed
class CircuitBreaker {
    private int    $failures  = 0;
    private string $state     = 'closed'; // closed | open | half-open
    private ?int   $openedAt  = null;

    public function call(callable $fn): mixed {
        if ($this->state === 'open') {
            if (time() - $this->openedAt < 30) throw new CircuitOpenException();
            $this->state = 'half-open';
        }
        try {
            $result = $fn();
            $this->onSuccess();
            return $result;
        } catch (\Throwable $e) {
            $this->onFailure();
            throw $e;
        }
    }
    private function onSuccess(): void {
        $this->failures = 0;
        $this->state    = 'closed';
    }
    private function onFailure(): void {
        if (++$this->failures >= 5) { $this->state = 'open'; $this->openedAt = time(); }
    }
}

Added 15 Mar 2026
Edited 25 Mar 2026
Views 24
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S
No pings yet today
Amazonbot 7 Perplexity 5 Unknown AI 3 Ahrefs 2 Google 1 ChatGPT 1
crawler 19
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Wrap calls to external services with a circuit breaker — after N failures open the circuit and return a fallback immediately without calling the failing service
📦 Applies To
PHP 5.0+ web api queue-worker
🔗 Prerequisites
🔍 Detection Hints
External HTTP API call with no timeout circuit breaker or fallback; cascading failures when dependency goes down
Auto-detectable: ✗ No blackfire datadog
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: File Tests: Update

✓ schema.org compliant