Circuit breaker with Resilience4j

Reading Time: 4 minutes

In this article we will be talking about a fault tolerance library i.e. Resilience4j has suddenly become so popular when it comes to handling faults, we have seen Netlfix’s Hystrix which is also a fault tolerance library. However, the support for it has been stopped. Also, this library was not capable of handling the asynchronous call but the Resilience4j is designed for Java8 and functional programming. Resilience4j enables the resilience in complex distributed systems where failure might take place. The library is considered to be very lightweight as it is only dependent on VAVR(which is also a functional programming library) and nothing else. Resilience4j would provide you higher-order functions to enhance any functional interface, lambda expression, or method reference with a Circuit Breaker, Rate Limiter, Retry, or Bulkhead, this apparently shows Resilience4j has got good support with functional programming.

Resiliene4j Modules

Resilience4j has got several core modules and add on modules from which you can choose what you want, you don’t have to go for all the modules. If you want to go with all the modules you can simply go for resilience4j all. Let’s talk about Resilience4j modules in detail.

Resilience4j has the following 6 core modules.

  • resilience4j-circuitbreaker: Circuit breaking
  • resilience4j-ratelimiter: Rate limiting
  • resilience4j-bulkhead: Bulkheading
  • resilience4j-retry: Automatic retrying (sync and async)
  • resilience4j-cache: Result caching
  • resilience4j-timelimiter: Timeout handling

Resilience4j has got several other modules as we talked above. Following are the other modules in Resilience4j

  • add-on modules
  • framework modules
  • reactives modules
  • metrics modules
  • 3rd party modules

Now we learned about all the modules which Resilien4j has but today we will be talking about the Circuit breaker module. The circuit breaker has been really popular when it comes to writing reactive services. So, to learn more about the Circuit breaker module, let’s first explore what is circuit breaker and how it actually works behind the scene.

What is Circuitbreaker?

The circuit breaker is essentially a pattern that helps to prevent cascading failures in a system. The circuit breaker pattern allows you to build a fault-tolerant and resilient system that can survive gracefully when key services are either unavailable or have high latency. Circuit breaker pattern is generally used in microservices architecture where there are multiple services involved but it can be used otherwise as well.

The circuit breaker has the following 3 states
Closed – Closed is when everything is normal, in the beginning, it will be in the closed state and if failures exceed the threshold value decided at the time of creating circuit breaker, the circuit will trip and go into an open state.

Open – Open is the state when the calls start to fail without any latency i.e calls will start to fail fast without even executing the function calls.

Half-open – In half-open state what will happen is, the very first call will not fail fast and all other calls will fail fast just as in the open state. If the first call succeeds then the circuit will go in the closed state again and otherwise, it will go into the open state again waiting for the reset timeout.

The figure below will help you understand the flow of a circuit breaker pattern.
circuit_breaker

Alright, that was all about, what is a circuit breaker and how it works behind the scenes. We will now look at the ways, how we can actually set up circuit breaker pattern for a spring-boot 2 service.

Let’s set up a Springboot project with service users where we could get users. We will be using the Maven build tool to set up the project structure here.

Pre-requisite for project

  • Maven
  • Java8 or higher
  • Springboot 2
  • Resilience4j library

Circuitbreaker with SpringBoot

Step1. Add the resilience4j maven dependency

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

Step2. Write the entry point for the project i.e Application.java 

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Step3. Create an application.properties file with all the configurations(can be found in the GitHub link shared below).

Step4. Write the controller class which will have the following endpoints.
The method below is used for successful calls i.e the method below would not cause an exception and works as expected in all the given scenarios if applicable.

// Success
@GetMapping("success/users")
@CircuitBreaker(name = USER_SERVICE)
public Mono<ResponseEntity> getUser(@PathVariable String id) throws Exception {
return Mono.just(ResponseEntity.ok(User.builder().id("1").name("Deepak").build()));
}

view raw
resilience4j_success
hosted with ❤ by GitHub

The method below is used for failed requests which will essentially cause the exception and once the exception count reaches the threshold value defined in configurations, it will open up the circuit breaker.

// Failure
@GetMapping("failure/users")
@CircuitBreaker(name = USER_SERVICE)
public Mono<ResponseEntity> getUserWithFailure() {
// This will cause the circuit breaker to go in an open state.
return Mono.error(new TimeoutException("Timeout exception occurred."));
}

view raw
resilience4j_failure
hosted with ❤ by GitHub

The method below is used to support the fallback method where if a call fails it will immediately invoke the fallback method as mentioned below. So, if the fallback method also fails multiple times(i.e the failure count reaches the threshold value) the circuit breaker will go in an open state, if it does not fail, the request will continue to serve the response.

// With Fallback
@GetMapping("/fallback/users")
@CircuitBreaker(name = USER_SERVICE, fallbackMethod = "getUserFallback")
public Mono<ResponseEntity> getUserWithFallback() {
// This will cause the exception and control will be transferred to fallback method.
return Mono.error(new TimeoutException("Timeout exception occurred."));
}

The method below is a fallback method that will be invoked once the parent method fails for some reason or the downstream service is down.

private Mono<ResponseEntity> getUserFallback() {
// You can fetch the value from cache here when the service is down, if the
// fallback method also cause any exception the circuit breaker will go in
// open state accordingly after multiple failed requests(Please check
// configurations for that).
return Mono.just(ResponseEntity.ok(User.builder().id("1").name("Deepak").build()));
}

@CircuitBreaker annotation is the annotation that will invoke the circuit breaker when anything goes wrong in the application. This annotation takes two parameters, first being the service name which is also mentioned in the configuration, the second being the fallback method name which is optional.
To check, if the circuit breaker actually goes into the open state or other for that matter, you need to have the said(as mentioned in the application.yaml file) failed requests. If you fail to do it manually i.e open the circuit, you can make use of tools like Apache Bench (ab), Apache bench is a tool used for load testing and benchmarking tool for the HTTP server. Also, you can use Apache Jmeter which is again a load testing tool. Once the circuit breaker goes into an open state the calls will start to fail fast i.e without any delay.

That’s pretty much it from the article, full code can be found on the GitHub repository, feel free to fork it. If you have any feedback or queries, please do let me know in the comments. Also, if you liked the article, please give me a thumbs up and I will keep writing blogs like this for you in the future as well. Keep reading and Keep coding 🙂


Knoldus-blog-footer-image

Written by 

Deepak is a Software Consultant having experince of more than 5 years . He is very enthusiastic towards his work and is a good team player. He has sound knowledge of different technologies which include Java, C++, C, HTML, CSS, Javascript, C# always keen to learn new technologies.