Resilience4j Circuit Breaker With Spring boot

What is a Circuit Breaker pattern?

The circuit breaker pattern is something that can prevent from repeatedly trying to call a service or a function that will likely fail and save CPU cycles.

It is pretty common for a software service to call remote software service and the remote service can fail or not respond as expected and this is pretty common in a microservice architecture when you have hundreds of clients calling the service which is failing eventually all the resources get used up, that is why it is a best practice to implement circuit breaker pattern in those scenarios.

How does Circuit Breaker work?

Circuit Breaker has three states Closed State, Open State, Half Open State. The image below shows how the flow from one state to another changes. The Circuit Breaker will be in the Closed state when everything is running as expected when failure starts coming it waits until the set threshold limit is reached then goes to Open state. While in Open states no calls will be going to failing remote service until certain wait time, then it goes to Half-Open state, in this stage reduced amount of calls goes to remote service to make sure the calls are successful, IF the calls are responding as expected it will go to Closed state or it goes back to Open state avoiding calls to failing remote service.

Circuit Breaker Pattern Java, resilience4j
Circuit Breaker Pattern.

What is Resilience4j?

Resilience4j is a lightweight, easy-to-use fault tolerance library designed for Java 8 and functional programming, it is a lightweight as it doesn’t depend on any other external libraries.

Implementation with Spring boot2

Add the dependency to pom.xml

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

Add the required configurations to application.yml file or application.properties file

resilience4j:
  circuitbreaker:
    configs:
      default:
        registerHealthIndicator: true
        slidingWindowSize: 10
        minimumNumberOfCalls: 5
        permittedNumberOfCallsInHalfOpenState: 3
        automaticTransitionFromOpenToHalfOpenEnabled: true
        waitDurationInOpenState: 5s
        failureRateThreshold: 50
        eventConsumerBufferSize: 10
        recordExceptions:
                - org.springframework.web.client.HttpServerErrorException
                - java.util.concurrent.TimeoutException
                - java.io.IOException
    instances:
      mainService:
        baseConfig: default

The above is the base configuration for resilience4j, waitDurationInOpenState is how much time the circuit breaker will be in Open state before it goes to Half-Open state .
failureRateThreshold sets the threshold limit before it goes to the open state.
recordExceptions records the type of exception on which you want your circuit breaker to be activated.

You can have multiple profiles for different service calls or operations, the above configuration has just one profile default, which is assigned to the mainService declared in the below class.

package com.springsleuth.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

@RestController
public class MainServiceController {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(MainServiceController.class);
	
	private static final String MAIN_SERVICE = "mainService";
	
	@Autowired
	private RestTemplate restTemplate;
	
	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}
	
	
	@GetMapping("/getSleuthTest")
	@ResponseStatus(HttpStatus.OK)
	@CircuitBreaker(name = MAIN_SERVICE, fallbackMethod="testFallBack")
	public ResponseEntity<String> getSleuthTest(){
		LOGGER.info("I'm here in main service calling service one");
		String response = restTemplate.getForObject("http://localhost:8081/serviceOne", String.class);
		return new ResponseEntity<String>(response, HttpStatus.OK);
		
	}
	
	
	private  ResponseEntity<String> testFallBack(Exception e){
		return new ResponseEntity<String>("In fallback method", HttpStatus.INTERNAL_SERVER_ERROR);
	}

}

In the above class, we activated circuit breaker using @CircuitBreaker annotations, it has two parameters.
1) service name, which is the service name defined in the config file (mainService) with default profile.
2) fallBackMethod, which is called when an error occurs, fallBackMethod is optional.

Here is the video explanation of it.

Resilience4j Circuit Breaker