The Circuit Breaker framework- Resilience4j is required in your microservice if you want to satisfy below questions:
- Do you want a fallback response if service is down ?
- Do you want to retry request ?
- Do you want to rate limit ? (What is Rate Limit ? To allow specific number of calls in a specific period of time is called rate limit. For eg., to allow 1000 calls in 10 seconds)
The above 1st question can be handled without implementing the Circuit Breaker framework just by returning a dummy response from your code, but 2nd and 3rd questions can’t be handled without implementing the same.
Previously we used to use Hystrix framework for the same, but now the latest technology is Resilience4j.
For resilience4j to work in your microservice you need below 3 dependencies:
- Resilience4j
- Spring Boot Actuator
- Spring Boot AOP
Add manually the AOP dependency as its not available in the Spring Initializr.
You can see all the dependencies below:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
There are many different features in Resilience4j framework as per below list:
- @Retry => Only retry mechanism
- @CircuitBreaker => This is the Circuit Breaker framework.
- @RateLimiter => How many call you want to do in a specific time.
- @Bulkhead => How many concurrent calls you want to make.
In this tutorial we would be discussing mainly about @CircuitBreaker.
If you open the official document of Resilience4j CircuitBreaker you can see below pic depicting 3 states:
Lets create a microservice called microservice-6 which would be calling another service called microservice-5. We will implement the Resilience4j in the microservice-6 because this service will have to react in a good way when microservice-5 is not available.
Here is the GitHub source code:
https://github.com/heapsteep/microservice-5.git
https://github.com/heapsteep/microservice-6.git
Suppose you have a Rest endpoint called “/api6” in microservice-6 like below:
@RestController public class MyController { private Logger logger=LoggerFactory.getLogger(MyController.class); @GetMapping("/api6") @CircuitBreaker(name="my-circuit-breaker-1", fallbackMethod="method1") public String sampleApi() { ResponseEntity<String> responseEntity= new RestTemplate().getForEntity("http://localhost:8081/api5", String.class); return responseEntity.getBody(); } public String method1(Exception e) { return "fallback response"; } }
In application.properties file add below items:
resilience4j.circuitbreaker.configs.default.registerHealthIndicator= true resilience4j.circuitbreaker.configs.default.eventConsumerBufferSize= 10 resilience4j.circuitbreaker.configs.default.automaticTransitionFromOpenToHalfOpenEnabled= true resilience4j.circuitbreaker.configs.default.failureRateThreshold= 50 resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls= 1 resilience4j.circuitbreaker.configs.default.permittedNumberOfCallsInHalfOpenState= 1 resilience4j.circuitbreaker.configs.default.slidingWindowSize= 10 resilience4j.circuitbreaker.configs.default.waitDurationInOpenState= 15s resilience4j.circuitbreaker.configs.default.slidingWindowType= COUNT_BASED resilience4j.circuitbreaker.instances.my-circuit-breaker-1.baseConfig= default management.health.circuitbreakers.enabled= true management.endpoints.web.exposure.include= health management.endpoint.health.show-details= always
First check whether microservice-5 is up.
Then call below api endpoint that should return success:
Start the microservice-6 application and hit the below endpoint. It will call the above endpoint internally and should return success like below:
If you check the health of microservice-6 one can see like below:
Lets make the microservice-5 down by shutting the server.
Lets again invoke the same above microservice-6 endpoint. One could see results like below:
Now If you check the health one can see this :
Above result is because of below added item, i.e., after 1 call circuit breaker should come to action.
resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls= 1
Hit once again:
Above result is due to below item. i.e., after 1 call the HALF_OPEN state will be converted to OPEN state:
resilience4j.circuitbreaker.configs.default.permittedNumberOfCallsInHalfOpenState= 1
You can go through the official documentation of Circuit Breaker mentioned above to see the meaning of other properties.