Categories
World Tech

Enforcing Resilience in a Spring Boot App using Resilience4J

Resilience4J is a Java library that allows you to add resilience in your JVM based applications.

This post is a part of a series on resilience, as we learn about resilience, design features and methods.

Resilience is an important feature of modern web applications. Simply put, fault tolerance is the ability of a system function to fail gracefully without the entire system suffering. In the case of web applications, we want to ensure that the whole system does not fail if a remote service (database, API server) fails (is slow or does not work).

What is Resilience4J?

Resilience4J is a lightweight, easy-to-use fault tolerance library inspired by Netflix Hystrix, but designed for Java 8 and functional programming.

Resilience modules provided by Resilience4J

Resilience4J offers a range of modules. Each module is a model of sustainability and can be implemented independently. Resilience4J provides a dependency for each of the following modules. However, if you want to use them all in your project, you can directly import the starter project provided by Resilience4J. It contains the required dependencies for all modules. The following figure shows the dependencies of the individual modules from the MVN repository. To distinguish them from each other, you can refer to the artifact ID of each dependency. word-image-4020

Circuit breaker

If the number of errors registered when accessing a service exceeds a certain threshold, access to this service becomes unavailable (fail-fast) or a fallback is performed. The following finite state machine describes the operation of a circuit breaker. word-image-11747

Reassembly

Here, each remote service call has its own thread pool. This prevents the entire system from becoming slow and freezing when a particular service is slow. If there are no threads available in the pool to make a remote call, a fallback option is provided. This model can also be implemented with semaphores, but thread pools are preferred.

repeats

A maximum number of remote service call attempts is specified if an error occurs. There may also be a fallback option if the call still fails on the last attempt.

Speed limiter

As the name implies, this module is used to limit the speed at which a remote maintenance call is made. There may be a response when a call is made to a remote service if the call frequency has already been exceeded.

Time limiter

This allows you to limit the amount that can be spent on a call. This is similar to the timeout for HTTP calls. If the time limit is exceeded, a back-up method may be provided.

Aspect sequence

When you apply multiple templates to a service call, they are executed in a specific order. By default, Resilience4J uses the following sequence:

  1. Reassembly
  2. Time Limiter.
  3. Speed limiter.
  4. Circuit breaker
  5. Repeat

Prepare specifications for module

Resilience4J offers two ways to create specifications for each of the above modules: via an application.yml file or by defining a customization bean. The job definition replaces the information in application.yml. The following is an example of the determination of certain characteristics for a circuit breaker. You can see how we can create specifications for other modules in the Hand-on Code section.

Using the application.yml

resist4j : switch : instances : cb-instanceA : failure-rate-threshold : 60 #Threshold value in percent above which the circuit breaker switches from closed to open. Waiting time with open condition : 5000 #Time in milliseconds that the dispenser must remain open before it enters the half-open state Number of calls allowed in the half-open state : 10 Minimum number of calls : 10 #Number of calls after which the error rate is calculated. To test it, I gave it a small value.

Use of the definition of beans

@Bean public CircuitBreakerConfigCustomizer circuitBreakerConfigCustomizer() { return CircuitBreakerConfigCustomizer.of(cb-instanceB,builder -> builder.minimumNumberOfCalls(10) .permittedNumberOfCallsInHalfOpenState(15)); }

Practice code

Below is a simple project that shows how to use each pattern. The specification features of each module are very clear. We will define the specifications via the application.yml file.

Mavens pom.xml

4.0.0 org.springframework.boot spring-boot-starter-parent 2.4.4 com.resilience demo 1.0.0 Resilience4J demo Resilience4J 1.8 org.springframework.boot spring-boot-starter-web io.github.resilience4j resilience4j-spring-boot2 1.7.0 org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-devtools org.springframework.boot spring-boot-maven-plugin Resilience4J requires Spring AOP to enable annotations.

Application.yml

resist4j : switch : instances : cb-instanceA : failure-rate-threshold : 60 #Threshold value in percent above which the circuit breaker switches from closed to open. Waiting time with open condition : 5000 #Time in milliseconds that the dispenser must remain open before it enters the half-open state Number of calls allowed in the half-open state : 10 Minimum number of calls : 10 #Number of calls after which the error rate is calculated. I gave it a small value for testing purposes. ratelimiter: instances: rl-instanceA: limit-refresh-period: 200ns limit-for-period: 40 # Maximum number of calls that can occur in the time specified by limit-refresh-period timeout-duration: 3s # Maximum time a call can last thread-pool-bulkhead: instances: tp-instanceA: queue-capacity: 2 #Number of calls that can be queued when the thread pool is full core-thread-pool-size : 4 #Number of threads available in the thread pool. timelimiter: instances: tl-instanceA: timeout-duration: 2s #Maximum duration of a call cancel-running-future: false #Cancel scheduled running futures after timeout. retry: instances: re-instanceA: max-attempts: 3 wait-duration: 1s # After this time, the call is considered failed and is retried retry-exceptions: # List of exceptions that throw a retry – java.lang.RuntimeException – java.io.IOException

Service class

@Service public class DemoService { @CircuitBreaker(name = cb-instanceA,fallbackMethod = cbFallBack) public String circuitBreaker() { return cbRemoteCall(); } private String cbRemoteCall() { double random = Math.random(); /must fail more than 70% of the time if (random <= 0.7) { throw new RuntimeException(CB Remote Call Fails); } return CB Remote Call Executed; } public String cbFallBack(Exception) { return String.format(Fallback Execution for Circuit Breaker. Error message: %sn,exception.getMessage()); } @RateLimiter(name = rl-instanceA) public String rateLimiter() { return Executing Rate Limited Method; } @TimeLimiter(name = tl-instanceA) public CompletableFuture timeLimiter() { return CompletableFuture.supplyAsync(this::timeLimiterRemoteCall); } private String timeLimiterRemoteCall() { /miss occurs 50% of the time double random = Math.random(); if (random < 0.5) { return Timed call has been executed…. } else { try { System.out.println(Delayed execution); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } return Exception Will be Raised; } @Retry(name = re-instanceA) public String retry() { return retryRemoteCall(); } private String retryRemoteCall() { //80% of the time an error will occur double random = Math.random(); if (random <= 0.8) { throw new RuntimeException(Retry Remote Call Fails); } return Make a second remote call; } @Bulkhead(name = tp-instanceA, type = Bulkhead.Type.THREADPOOL) public String bulkHead() { return Executing Bulk Head Remote call; } }

Tax class

@RestController @RequestMapping(/resilience) public class DemoController { private final DemoService demoService ; public DemoController(DemoService demoService) { this.demoService = demoService; } @GetMapping(/cb) public String circuitBreaker() { return demoService.circuitBreaker(); } @GetMapping(/bulkhead) public String bulkhead() { return demoService.bulkHead(); } @GetMapping(/tl) public CompletableFuture timeLimiter() { return demoService.timeLimiter(); } @GetMapping(/rl) public String rateLimiter() { return demoService.rateLimiter(); } @GetMapping(/retry) public String retry() { return demoService.retry(); } }

Supplement

Beginners usually don’t pay attention to durability. I think by now you’ve seen how necessary and useful it is to develop a powerful web application. I suggest you study the specifications of each module to see how to use them effectively. I hope you found this guide useful. Until the next lesson.

Frequently Asked Questions

Is Resilience4j better than Hystrix?

As you may already know in this age of social media, we can observe the behavior pattern of each and every person. We can understand the causes of every action and the consequences of the actions. The things that follows next is obvious. At every point in time we can also predict the action that a person might take next. This is not a subject-verb agreement problem. It is a scenario where the actions are triggered in the future. This can be done using a library such as Resilience4j. Hystrix is a modern Java library that helps you to implement resilient applications in a very simple way. From the docs: “Hystrix provides a very easy way to implement resilient applications, but it is a very traditional approach.”

What is Resilience4j spring boot2?

One of the big topics in software engineering nowadays is resilience. So, I figured I write a blog about it. Spring Boot is a modern, lightweight, and highly productive JavaEE web framework, with a focus on providing an extensible platform for microservices.  Spring Boot has become a popular choice for Java developers who want to build fast, large-scale applications.  Most Spring Boot applications are automatically configured with Spring Boot’s default configuration and some small extras that make development straightforward.  However, it is not uncommon for an application to run into a configuration problem, which can be time consuming and frustrating.

What is Resilience4j?

Today we’re going to take a look at Resilience4J, a library that provides a resilient (also called fault-tolerant) context for Spring Web MVC applications. We’re going to look at how resilient operations are executed in a resilient context using the Resilience4J library from the Spring Framework. While working on my last blog post, I found myself wanting to create an application that enforced resilience with a Spring Boot Application. However, I was not really sure how to implement that, so I decided to use Resilience4J and see what I could come up with.

Related Tags:

resilience4j retry spring boot exampleresilience4j-spring boot microservicesresilience4j-spring-boot mavenresilience4j-reactor exampleresilience4j circuit breaker spring boot exampleresilience4j timelimiter spring boot example,People also search for,Feedback,Privacy settings,How Search works,resilience4j circuit breaker spring boot example,resilience4j timelimiter spring boot example,resilience4j retry spring boot example,resilience4j-spring boot microservices,resilience4j-spring-boot maven,resilience4j rate limiter spring boot example,resilience4j-reactor example,resilience4j circuit breaker spring boot 2 example

Leave a Reply

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