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.
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.
If you are a video person here is the video tutorial
Please show some love and subscribe to my channel Subscribe Hacker Heap.
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.
Top comments (4)
Thanks for the write up.
Incase of application.properties , how do I need to specify this:
recordExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.util.concurrent.TimeoutException
- java.io.IOException
In Resilience4j Circuit Breaker, do we have any configuration to retry particular number of times when the circuit is OPEN? or we need to use Retry configuration to achieve the same?
Are you the author of this lib?
No I’m not