Circuit Breaker Pattern Implementation

Implementing the Circuit Breaker Pattern in .NET Core for Robust Microservices

The Circuit Breaker pattern is a critical component of building resilient microservices architectures. It helps systems gracefully handle failures by preventing cascading errors and allowing recovery when conditions improve. This article will explore how to implement the Circuit Breaker pattern using Polly, an open-source resilience framework for .NET.

📹 Watch the Video Tutorial

Watch the complete walkthrough in the video above for step-by-step guidance.

Understanding the Circuit Breaker Pattern

The Circuit Breaker pattern is a design principle used in software development to prevent a system from repeatedly attempting a failing operation. Instead, it temporarily stops making requests until conditions improve or after a predefined timeout. This approach helps maintain system stability and prevents service degradation.

Key Concepts

  • Closed State: The normal state where the circuit breaker allows requests to pass through.
  • Open State: When a threshold of failures is reached, the circuit breaker trips and stops allowing requests until it transitions back to the half-open state.
  • Half-Open State: After a timeout, the circuit breaker allows a limited number of requests through to test if the underlying service has recovered.

Implementing Circuit Breaker in .NET Core

In this section, we will walk through implementing the Circuit Breaker pattern using Polly. We will create a simple microservices architecture with two services: an API Gateway and a downstream service.

Setting Up the Project

To start, create a new .NET Core solution with two projects:

  • ApiGateway: An ASP.NET Core Web API project acting as the entry point for client requests.
  • DownstreamService: A simple service that the ApiGateway will call to perform operations.

Installing Polly

Add the Polly NuGet package to both projects. You can do this via the NuGet Package Manager or using the dotnet CLI:

BASH

dotnet add package Polly

Implementing the Circuit Breaker Logic

In the ApiGateway project, we will implement the Circuit Breaker logic to handle calls to the DownstreamService.

Creating a Policy

Polly provides a fluent API to define resilience strategies. We will create a policy for breaking the circuit when the downstream service returns an error response.

CSHARP

public static IServiceCollection AddResilience(this IServiceCollection services)
{
    var policyRegistry = services.AddPolicyRegistry();

var breakPolicy = Policy .Handle<HttpRequestException>() .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (outcome, timespan, retryAttempt, context) => { // Log the retry attempt }) .CircuitBreakerAsync(5, TimeSpan.FromMinutes(1), onBreak: (exception, breakDuration) => { // Log the circuit breaking event }, onReset: () => { // Log the circuit reset event });

policyRegistry.Add("breakerPolicy", breakPolicy);

return services; }

Applying the Policy

We will apply the Circuit Breaker policy to the HTTP client used by the ApiGateway to call the DownstreamService.

CSHARP

services.AddHttpClient<IDownstreamClient, DownstreamClient>(client =>
{
    client.BaseAddress = new Uri("https://downstreamservice.com/");
})
.AddTransientHttpErrorPolicy(p => p.GetRegistry().Get("breakPolicy"));

🧪 Testing the Circuit Breaker

To test the Circuit Breaker, we need to simulate failures in the DownstreamService.

Simulating Failures

In the DownstreamService, modify the endpoint that the ApiGateway calls to return an error response after a certain number of requests.

CSHARP

[ApiController]
[Route("api/[controller]")]
public class FailController : ControllerBase
{
    private int _requestCount = 0;

[HttpGet] public IActionResult Get() { _requestCount++; if (_requestCount > 5) { return StatusCode(500, "Service is unavailable"); }

return Ok("Success"); } }

Running the Tests

Start both services and make requests to the ApiGateway. After a few successful calls, the DownstreamService will start returning errors. The Circuit Breaker should trip after five consecutive failures, preventing further requests for one minute.

Advanced Features of Polly

Polly offers several advanced features that can be integrated with the Circuit Breaker pattern to enhance its functionality.

Fallback Policy

A fallback policy allows you to specify an alternative action when the Circuit Breaker is open or a request fails. For example, you could return a cached response or a default value.

CSHARP

var breakPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
        (outcome, timespan, retryAttempt, context) =>
        {
            // Log the retry attempt
        })
    .CircuitBreakerAsync(5, TimeSpan.FromMinutes(1),
        onBreak: (exception, breakDuration) =>
        {
            // Log the circuit breaking event
        },
        onReset: () =>
        {
            // Log the circuit reset event
        })
    .FallbackAsync((context, token) => Task.FromResult<HttpResponseMessage>(new HttpResponseMessage()
    {
        StatusCode = HttpStatusCode.ServiceUnavailable,
        Content = new StringContent("Service is currently unavailable. Please try again later.")
    }));

🎯 Best Practices and Common Pitfalls

Implementing the Circuit Breaker pattern effectively requires careful consideration of several best practices and potential pitfalls.

Choose Appropriate Thresholds

Selecting the right thresholds for failure counts and timeout durations is crucial. Too low a threshold may cause premature circuit breaking, while too high a threshold could delay recovery.

Monitor Circuit States

Implement logging or monitoring to track the state transitions of your Circuit Breakers. This will help you quickly identify issues and make informed decisions during runtime.

Related: Polly Retry Policies: Ensuring Reliability in .NET Cor…

Related: Polly Retry Policies: Ensuring Reliability in .NET Cor…

🌍 Real-World Use Cases

The Circuit Breaker pattern is widely used in various scenarios, including:

  • Microservices Communication: Ensuring resilience when calling external services.
  • Database Access: Handling transient database failures gracefully.
  • Third-Party APIs: Protecting against external service outages.

🎓 Conclusion

The Circuit Breaker pattern is an essential tool for building resilient microservices architectures. By implementing it using Polly, developers can improve the stability and reliability of their applications. Remember to carefully configure thresholds, monitor states, and integrate advanced features like fallbacks to maximize the effectiveness of your Circuit Breakers.