Understanding Circuit Breakers: A Complete Guide

Imagine your favourite streaming app crashes during peak hours r an e-commerce site freezes during a flash sale, because one recommendation service fails. Sound familiar? In microservices, a single weak link can drag down the entire system. That’s where the Circuit Breaker pattern comes in— a architecture pattern inspired by electrical fuse that trips when there’s an overload. The goal is to protect the system and keep it working even if a others part goes down. Let’s break down why it matters and how to use it effectively.

Definition of Circuit Breaker

A Circuit Breaker in software tracks the calls from one service to another. as mentioned earlier it mirrors the idea of a power switch tripping to save an electrical circuit due to high current. When error rates go too high, it blocks further calls for a while and after a cooldown, it tests if the remote service is healthy again. If it is, traffic resumes. If not, it stays open to avoid more failures. No more cascading failures. No more angry users. Just controlling behaviour due to other service fail.

But why is this critical for microservices?

Microservices Need Guardrails

In a distributed system, services depend on each other. In my career I meet situations like of slow payment gateway processing or faulty recommendation API might that completely your blocked operability of application. The Circuit Breaker tackles three big issues:

  • Preventing System Overloads: Stopping repeated calls to failing services, safeguards the system from being overwhelmed.

  • Isolating Service Failures: Separates issues from individual services, preventing them from affecting the entire system.

  • Enhancing Resilience and Reliability: With controlled and managed failure responses, the overall system remains stable and can recover gracefully.

When developers are using this pattern, it gives them super power to isolates issues and don’t let them to escalate into critical system-wide outages. While leading a team to implement PSD2-compliant payment systems, we used Circuit Breakers to handle third-party bank API failures. Without them, small error prone API that calculates payment fee was able to break entire payment flow but we used circuit breaker pattern to boosts user trust and avoids widespread service interruptions.

The Three States of a Circuit Breaker

Working mechanism of the Circuit Breaker pattern is quite simple. Pattern operates in three basic states:

StateWhat dose it mean
ClosedThe service is operating normally, and all requests are routed directly to it.
OpenMultiple failures have triggered the circuit breaker(e.g., timeouts, 500 responses) that causes block of subsequent requests to prevent further stress on the service.
Half-OpenA limited number of requests are allowed to test if the service has recovered. If successful response occurred, the breaker resets state to Closed otherwise, it returns state to Open.

They allow system to adapt dynamically to real-time conditions, allowing for both protective blocking during failures and cautious testing during recovery.

Supplementary patterns

Above base pattern works fine in most of cases but sometimes requirements could be more sophisticated. There are couple enhancements that could be applied to base mechanism:

  • Retry pattern: Automatically reattempts operations after transient failures, reducing the probability of tripping the circuit breaker unnecessarily. But You have to be careful with using that. Many retries don’t implicit that target service didn’t received request. Maybe there was some short network failures during getting response.

  • Timeout pattern: Enforces a maximum wait period for service responses, ensuring that delays result in prompt failure detection.

  • Fallback pattern: Provides an alternative action when a service is unavailable, maintaining functionality despite disruptions by serve as a safety net, ensuring that users still receive a response. There are many strategies to handle that pattern and You could choose one depending on your current requirements:

    • Returning Default Data: Usually provides static data when the service is unavailable.

    • Caching Results: Utilizes cached responses from previous successful calls.

    • Redirecting Requests: Forwards requests to alternative services that can handle the operation.

Combination of all above maximizes resource utilization and ensures that applications remain responsive and robust even amid network fluctuations and service hiccups, thereby effectively mitigating various failure scenarios encountered in distributed systems. These complementary patterns work seamlessly together to sustain uninterrupted service operation.

Tools for Implementing the pattern

There are many libraries and tools simplify the implementation of the Circuit Breaker Pattern but here I would like to recommend few of them:

  • Netflix Hystrix: Well-established tool for Java applications that isolates points of access between services and provides robust fallback options.

  • Resilience4j: Lightweight, modular, and functional Java library for Java 8 and newer that offers extensive customization for circuit breaking.

  • Spring Cloud Circuit Breaker: Provides a consistent API to various circuit breaker implementations, including Resilience4j.​

  • Polly: .NET library that allows developers to implement resilience strategies, including retry and circuit breaker policies, in a fluent and thread-safe manner.

  • Istio: Offers a more holistic approach by allowing us to enforce resilience policies at the network level, decoupling them from individual service implementations. It uses Envoy proxies to manage traffic between services, enabling the enforcement of circuit-breaking policies without altering application code. Thats crucial point by providing resilience without implementing fault tolerance in codebase especially if we are trying to provide pattern into legacy applications.

These tools are designed to integrate seamlessly with their respective platforms, allowing developers to focus more on business logic rather than low-level error handling.

Implementing the Circuit Breaker with Resilience4j in Spring Boot

As I most of my career spent of writing Java business applications I would like to provide comprehensive example of implementing pattern using Resilience4j:

  1. Add Dependencies: Include the Resilience4j starter in your pom.xml:​

     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
     </dependency>
    
  2. Configure the Circuit Breaker: Define properties in your application.yml:​

     resilience4j:
       circuitbreaker:
         configs:
           default:
             registerHealthIndicator: true
             failureRateThreshold: 50
             waitDurationInOpenState: 10s
             permittedNumberOfCallsInHalfOpenState: 3
             slidingWindowSize: 20
         instances:
           myService:
             baseConfig: default
    
  3. Apply the Circuit Breaker: Use the @CircuitBreaker annotation in your service:​

     @Service
     public class MyService {
    
         @CircuitBreaker(name = "myService", fallbackMethod = "fallbackMethod")
         public String callExternalService() {
             // Logic to call external service
         }
    
         public String fallbackMethod(Throwable throwable) {
             // Fallback logic
             return "Fallback response";
         }
     }
    
  4. Create Service: to call unhealthy service lets create​ controller:

     @GetMapping(value = "/get-my-service")
     public ResponseEntity<Response> getMyServicecall() {
        try {
            MyServiceResponse user = myServices.callExternalService();
            return new ResponseEntity<>(new Response(user,"external service called successfully", Boolean.TRUE), HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(new Response("Error during service call", Boolean.FALSE),
                    HttpStatus.INTERNAL_SERVER_ERROR);
        }
     }
    
  5. Use Spring Actuator: add Metrics to have full insignths:
    Add Dependency First

     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
     </dependency>
    

    After lets configure Spring to gather metrics from actuator:

     management:
       endpoint.health.show-details: always
       health.circuitbreakers.enabled: true
    

    Voila! Now you can mesure circuit breaker behaviour in Your application:

     {
         "status": "UP",
         "components": {
             "circuitBreakers": {
                 "status": "UNKNOWN",
                 "details": {
                     "myService": {
                         "status": "CIRCUIT_OPEN",
                         "details": {
                             "failureRate": "100.0%",
                             "failureRateThreshold": "50.0%",
                             "slowCallRate": "0.0%",
                             "slowCallRateThreshold": "100.0%",
                             "bufferedCalls": 3,
                             "slowCalls": 0,
                             "slowFailedCalls": 0,
                             "failedCalls": 3,
                             "notPermittedCalls": 2,
                             "state": "OPEN"
                         }
                     }
                 }
             }
         }
     }
    

Real-World and Personal Examples

In real world there are many places where You could use Circuit Breaker Pattern there are some common examples from real world:

  • A payment service in an online store often calls external gateways. If a gateway fails, the Circuit Breaker halts further attempts. Customers can still browse and place orders. Payment finalisation happens once the gateway is back.

  • Another scenario is a recommendation service in a streaming platform. It might query several external sources. If one source is slow or offline, the Circuit Breaker prevents repeated timeouts and offers fallback suggestions. This way, the main service remains usable.

But over the years, I have had hands-on experience with implementing and analyzing resilient architectures.

During my work on one of the biggest bank in Europe I have used it when payment fee calculation provided by external team constantly fails. We build mechanism that provides some default value with a range of possible fee.

Another great example were when I was integrate some document management system with OCR solution. Company where I have used this pattern had many OCR engines with different level of performance. When one which has better was failed we continue operating by calling second OCR engine with less performance. Backoffice were able to continue they work with some limits of performance. That was crucial trade-off between doing work slower or waiting with whole stack of documents to process.

Final Thoughts

The Circuit Breaker Pattern is a fundamental component in building resilient microservices architectures by providing prevention single-service failures from cascading into large-scale outages. By temporarily halting calls to an unstable or non-responsive service and gradually reintroducing them, the system remains protected against overload and maintains overall stability. Its provides key strategic benefits into Your system like Overload Prevention, Failure Isolation, Resilience & Reliability.

Combination of proactive failure detection with fallback strategies and leveraging powerful tools like Netflix Hystrix, Resilience4j, and Polly, architects and developers can build systems that are both robust and flexible.

Whether you’re dealing with payment gateways, recommendation engines, or any external integrations, applying the Circuit Breaker pattern ensures that a single failure doesn’t cripple your entire platform. Instead, the system intelligently adapts and recovers, offering users a stable and reliable experience.

0
Subscribe to my newsletter

Read articles from Konrad Jędrzejewski directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Konrad Jędrzejewski
Konrad Jędrzejewski