Circuit Breaker Pattern in C#: Definition, Architecture, Examples, Pros, and Cons
The Circuit Breaker Pattern is a resilience pattern in C# that prevents repeated calls to failing services by temporarily blocking requests after a failure threshold is reached.
The Circuit Breaker Pattern protects applications from cascading failures in distributed systems and microservices architectures. When repeated failures occur while calling an external service, API, database, or microservice, the circuit breaker automatically stops sending requests for a temporary period. This prevents resource exhaustion, improves system stability, and allows the failing service time to recover. In C#, the Circuit Breaker Pattern is commonly implemented using libraries such as Polly with ASP.NET Core and HttpClientFactory. The pattern is especially useful when working with unreliable external systems, cloud services, or network-dependent applications.
Why We Use Circuit Breaker Pattern in C#?
We use the Circuit Breaker Pattern to improve fault tolerance and prevent system-wide failures.
Main reasons include:
• Prevents cascading failures
• Protects system resources
• Improves application resilience
• Reduces unnecessary network calls
• Helps failing services recover
• Improves response times during failures
• Prevents thread exhaustion
• Works well with microservices
• Enhances fault isolation
• Supports self-healing systems
Real-World Analogy
A household electrical circuit breaker stops electricity flow when overload occurs.
Software equivalent:
Too many failed requests
-> Circuit opens
-> Requests blocked temporarily
-> Service recovers
-> Circuit closes again
Circuit Breaker States
The Circuit Breaker has three main states.
1. Closed State
Normal operation:
Requests allowed
Failures monitored
If failures exceed the threshold:
Circuit transitions to OPEN
2. Open State
Requests are blocked immediately.
No requests sent to failing service
After timeout expires:
Circuit transitions to HALF-OPEN
3. Half-Open State
Limited test requests are allowed.
If success -> CLOSED
If failure -> OPEN
Circuit Breaker Workflow
Request
|
Success?
|
YES ----------------> CLOSED
|
NO
|
Failure Threshold Reached?
|
YES ----------------> OPEN
|
Timeout Expires
|
HALF-OPEN
|
Test Request Success?
|
YES -> CLOSED
NO -> OPEN
When Should We Use Circuit Breaker Pattern?
The Circuit Breaker Pattern should be used when applications depend on external or unreliable systems.
Typical programming problems where Circuit Breaker is beneficial:
• External API communication
• Microservices architectures
• Database connectivity issues
• Cloud service integrations
• Payment gateways
• Distributed systems
• Network instability handling
• Long-running remote operations
• Service-to-service communication
Avoid Circuit Breaker Pattern for:
• Pure in-memory applications
• Local-only processing
• Simple CRUD systems without remote dependencies
• Very small applications
Circuit Breaker Pattern Examples in C#
Example 1: Basic Circuit Breaker Implementation in C#
// Simple Circuit Breaker Class
public class CircuitBreaker
{
private int _failureCount;
private readonly int _failureThreshold = 3;
private bool _isOpen;
private DateTime _lastFailureTime;
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(10);
public async Task ExecuteAsync(Func<Task> action)
{
if (_isOpen)
{
if (DateTime.UtcNow - _lastFailureTime > _timeout)
{
_isOpen = false;
}
else
{
throw new Exception("Circuit is OPEN");
}
}
try
{
await action();
_failureCount = 0;
}
catch
{
_failureCount++;
_lastFailureTime = DateTime.UtcNow;
if (_failureCount >= _failureThreshold)
{
_isOpen = true;
}
throw;
}
}
}
// Usage
var circuitBreaker = new CircuitBreaker();
await circuitBreaker.ExecuteAsync(async () =>
{
Console.WriteLine("Calling external API");
throw new Exception("API failed");
});
Example 2: Circuit Breaker with Polly
Install Package
dotnet add package Polly
// Polly Circuit Breaker Example
using Polly;
using Polly.CircuitBreaker;
var policy = Policy
.Handle<Exception>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(10)
);
try
{
await policy.ExecuteAsync(async () =>
{
Console.WriteLine("Calling API");
throw new Exception("Service unavailable");
});
}
catch (BrokenCircuitException)
{
Console.WriteLine("Circuit breaker is OPEN");
}
Example 3: Circuit Breaker with HttpClientFactory
// Service Registration
builder.Services.AddHttpClient("MyApiClient")
.AddTransientHttpErrorPolicy(policy =>
policy.CircuitBreakerAsync(
3,
TimeSpan.FromSeconds(15)
));
// Usage
public class ApiService
{
private readonly HttpClient _httpClient;
public ApiService(IHttpClientFactory factory)
{
_httpClient = factory.CreateClient("MyApiClient");
}
public async Task<string> GetDataAsync()
{
return await _httpClient.GetStringAsync(
"https://www.howcsharp.com/api/data");
}
}
Example 4: Half-Open State Simulation
public async Task SimulateHalfOpenAsync()
{
bool success = DateTime.UtcNow.Second % 2 == 0;
if (!success)
{
throw new Exception("Temporary failure");
}
Console.WriteLine("Service recovered");
}
Example 5: Circuit Breaker with Retry Pattern
Circuit Breaker is often combined with Retry Pattern.
var retryPolicy = Policy
.Handle<Exception>()
.RetryAsync(3);
var circuitBreakerPolicy = Policy
.Handle<Exception>()
.CircuitBreakerAsync(2, TimeSpan.FromSeconds(30));
var combinedPolicy = Policy.WrapAsync(
retryPolicy,
circuitBreakerPolicy
);
await combinedPolicy.ExecuteAsync(async () =>
{
Console.WriteLine("Executing request");
throw new Exception("Request failed");
});
Advantages of Circuit Breaker Pattern in C#
| Advantage | Description |
|---|---|
| Prevents Cascading Failures | Stops failures from spreading across systems. |
| Improves Resilience | Makes applications more fault tolerant. |
| Resource Protection | Prevents thread and connection exhaustion. |
| Faster Failure Detection | Fails quickly instead of waiting for repeated timeouts. |
| Supports Recovery | Allows failing services time to recover. |
| Works Well with Microservices | Improves distributed system stability. |
| Easy Integration | Libraries like Polly simplify implementation. |
Disadvantages (Weak Points) of Circuit Breaker Pattern in C#
| Disadvantage | Description |
|---|---|
| Additional Complexity | Requires state management and monitoring. |
| Temporary Request Blocking | Some valid requests may be rejected during OPEN state. |
| Difficult Configuration | Thresholds and timeout values require tuning. |
| False Positives | Temporary issues may incorrectly open the circuit. |
| Monitoring Overhead | Requires logging and observability tooling. |
| Not a Complete Solution | Should be combined with retries, timeouts, and fallbacks. |
Circuit Breaker vs Similar Patterns
| Feature | Circuit Breaker | Retry Pattern | Timeout Pattern | Fallback Pattern | Bulkhead Pattern |
|---|---|---|---|---|---|
| Main Goal | Prevent repeated failures | Retry transient failures | Limit wait duration | Provide alternative response | Isolate failures |
| Failure Handling | Blocks requests temporarily | Retries failed operations | Cancels long-running calls | Returns backup response | Limits resource sharing |
| Resource Protection | Excellent | Low | Moderate | Moderate | Excellent |
| Complexity | Medium | Low | Low | Medium | Medium |
| Best For | Unstable external services | Temporary network issues | Slow operations | Graceful degradation | Distributed systems |
| State Management | Yes | No | No | Optional | Yes |
| Works with Microservices | Excellent | Good | Good | Excellent | Excellent |
Common Real-World Use Cases
Payment Gateway Protection
Workflow:
Payment API fails repeatedly
-> Circuit opens
-> Requests blocked temporarily
External API Communication
Workflow:
Weather API unavailable
-> Prevent repeated calls
-> Use fallback response
Microservices Communication
Workflow:
Inventory Service unavailable
-> Circuit breaker activates
-> Prevent cascading failure
Popular C# Libraries for Circuit Breaker Pattern
| Library | Description |
|---|---|
| Polly | Most popular .NET resilience library. |
| Microsoft.Extensions.Http.Polly | ASP.NET Core integration for Polly policies. |
| Steeltoe | Cloud-native .NET resilience framework. |
| Resilience4j.NET | .NET adaptation of Java resilience patterns. |
| YARP | Reverse proxy supporting resilience middleware. |
Best Practices for Circuit Breaker Pattern
• Combine with Retry Pattern
• Use timeout policies
• Add logging and monitoring
• Configure thresholds carefully
• Use fallback mechanisms
• Monitor HALF-OPEN transitions
• Avoid excessive retries
• Test failure scenarios regularly
Summary
The Circuit Breaker Pattern is a resilience and fault-tolerance pattern in C# designed to prevent cascading failures in distributed systems and microservices. It temporarily blocks requests to failing services, allowing systems to recover while protecting resources and improving stability. The pattern is commonly implemented using Polly and ASP.NET Core HttpClientFactory. Although it introduces configuration and monitoring complexity, it is essential for building reliable cloud-native and distributed applications.
Data Management Patterns in C#
23. CQRS (Command Query Responsibility Segregation) in C#
24. Event Sourcing in C#
25. Saga Pattern in C#
26. Outbox Pattern in C#
Microservice Patterns in C#
27. Circuit Breaker Pattern in C#
28. Bulkhead Pattern in C#
29. Retry with Backoff Pattern in C#