If you've ever had a service call hammer a downstream dependency that was already down, you know what happens next. Timeouts pile up, threads get exhausted, and your healthy service starts failing because it won't stop talking to something that can't answer. Michael Nygard described the fix in "Release It!" and called it the Circuit Breaker pattern. It's one of the most useful patterns in distributed systems, and in C# you can implement it cleanly with Polly or roll your own.

How it actually works

The idea is borrowed from electrical engineering. When a circuit detects a fault, the breaker trips and stops current from flowing. In software, the circuit breaker sits between your code and an external service. It tracks failure rates. When failures cross a threshold, it "trips" and stops making calls to that service for a cooldown period. During that window, your code gets an immediate failure response or a cached fallback instead of waiting for a timeout.

The circuit breaker has three states. Closed means everything is normal and calls go through. Open means the breaker has tripped and calls are blocked. Half-open means the cooldown expired and the breaker lets a test request through to see if the service recovered. If that test succeeds, the breaker closes. If it fails, the breaker stays open for another cooldown period.

Building one in C#

In a basic implementation, you need a class that tracks failure count, knows the threshold, and manages the state transitions. The Execute method wraps your actual service call. If the circuit is open, it returns a fallback immediately instead of making the call. If the circuit is closed, it makes the call and increments the failure counter on exceptions. When failures hit the threshold, the state flips to open and a timer starts.

In practice, most teams use Polly for this. Polly gives you circuit breaker policies you can compose with retries, timeouts, and fallbacks. You define how many consecutive failures trigger the trip, how long the break lasts, and what happens during the break. It integrates cleanly with HttpClient through the IHttpClientFactory pattern in ASP.NET Core.

When to use it

Any time your service makes calls to something that can fail independently, a circuit breaker helps. Database connections, external APIs, downstream microservices, third-party integrations. The pattern prevents a single dependency failure from cascading through your entire system. Without it, one slow database can take down services that don't even use that database, just because thread pools get exhausted waiting.

The key thing to get right is your thresholds. Too sensitive and the breaker trips on transient blips. Too lenient and it doesn't protect you when things are actually broken. Start conservative and tune based on real traffic patterns.