The Circuit breaker pattern in Java

The Circuit Breaker pattern is used to prevent an application from performing an operation that is likely to fail. In microservices architecture, it’s commonly used to handle fault tolerance when calling external services that may fail or take a long time to respond.

Imagine a scenario where a microservice (Service A) calls another service (Service B). If Service B is down or slow to respond, without a circuit breaker, Service A will continue making requests, which may lead to cascading failures or resource exhaustion. The Circuit Breaker pattern “opens” and stops calling the failing service for a period to allow it to recover, then “closes” after the service is healthy again.

Key states of Circuit Breaker:

  1. Closed: The circuit breaker allows requests to pass through as normal.
  2. Open: The circuit breaker prevents requests from being sent, returning a fallback response immediately.
  3. Half-Open: The circuit breaker allows a limited number of requests to check if the service has recovered.

Implementation

There are different ways to implement Circuit Breaker pattern. In this case we’ll use Resilience4j for implementing the Circuit Breaker in Spring Boot. Add the following dependency to your pom.xml:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.7.0</version>
</dependency>

Here’s an example of how we might use a RestTemplate to call another service:

import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class ExternalService {
    @Autowired
    private RestTemplate restTemplate;
    public String callExternalService() {
        String url = "http://localhost:8081/external-api";
        return restTemplate.getForObject(url, String.class);
    }
}

This method will call an external API, but what happens if this API is down or slow? This is where the Circuit Breaker comes in.

To apply the Circuit Breaker, annotate the method that makes the external call using the @CircuitBreaker annotation.

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
@Service
public class ExternalService {
    @Autowired
    private RestTemplate restTemplate;
    private static final String EXTERNAL_SERVICE = "externalService";
    @CircuitBreaker(name = EXTERNAL_SERVICE, fallbackMethod = "fallbackResponse")
    public String callExternalService() {
        String url = "http://localhost:8081/external-api";
        return restTemplate.getForObject(url, String.class);
    }
    public String fallbackResponse(Throwable t) {
        return "External Service is currently unavailable. Please try again later.";
    }
}

@CircuitBreaker(name = "externalService"): This specifies that Resilience4j will manage the circuit breaker with the name externalService.

fallbackMethod = "fallbackResponse": If the circuit breaker is in the OPEN state, or if the call to the external service fails, this fallback method will be executed.

Now we can configure the circuit breaker properties in our application.yml file.

resilience4j.circuitbreaker:
  instances:
    externalService:
      slidingWindowSize: 5
      failureRateThreshold: 50
      waitDurationInOpenState: 10000
      permittedNumberOfCallsInHalfOpenState: 3
  • slidingWindowSize: The number of calls to evaluate for the failure rate,
  • failureRateThreshold: The percentage of failures that trip the circuit breaker. In this case, if 50% of calls fail, the circuit opens,
  • waitDurationInOpenState: The amount of time (in milliseconds) the circuit breaker stays open before transitioning to half-open state,
  • permittedNumberOfCallsInHalfOpenState: The number of calls to allow in the half-open state to check if the external service has recovered.

How it works

  1. Initially, the circuit breaker is in the Closed state. All requests pass through to the external service.
  2. If the failure rate (e.g., timeouts or errors) exceeds the failureRateThreshold, the circuit breaker transitions to the Open state. In this state, all requests are blocked, and the fallback method is executed.
  3. After the waitDurationInOpenState, the circuit breaker transitions to the Half-Open state, allowing a limited number of requests to check if the service has recovered.
  4. If the service responds successfully during the Half-Open state, the circuit breaker transitions back to Closed. Otherwise, it reopens.

Summary

The Circuit Breaker pattern prevents continuous calls to a failing service, providing a graceful degradation (using the fallback method) while the service recovers. Using Resilience4j with Spring Boot simplifies the implementation, allowing you to control fault tolerance with minimal effort.

Leave a Reply

Your email address will not be published. Required fields are marked *