x Java Java 8 JUnit JSON
  • XML
  • JDBC Spring Boot Microservices React Contact Us

    Spring Boot Circuit Breaker Resilience4j example

    When we call a service A from another service B and service A doesn't provide any response for long time, then we can implement Circuit Breaker in service B as to prevent unnecessary calls and take appropriate action. Circuit Breaker also provides a fallback mechanism to handle service call failure gracefully. We can also configure after how many failed calls, Circuit Breaker would be turned on or after home much time to wait for state to change from open to half-open.

    Resilience4j library provide fault tolerance in microservice applications. It provides Circuit Breaker, Retry, Bulkhead, Rate Limit, Fallback capabilities for fault tolerance. Below example shows how to implement Circuit Breaker and Fallback in a Spring Boot application using Resilience4j.

    1) Create CourseServiceApplication

    First let us create a Spring Boot based CourseService application which provided list of courses available.

    Step 1) Create pom.xml file and add spring-boot-starter-web dependency

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>        

    Step 2) Create Course, CourseRestController, CourseServiceApplication classes to create Course microservice

    public class Course {
        private int id;
        private String description;
        // removed getters and setters
    }  
    package com.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class CourseServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CourseServiceApplication.class, args);
        }
    
    }  
    import java.util.ArrayList;
    import java.util.List;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class CourseRestController {
    
    	private static final Logger LOG = LoggerFactory.getLogger(CourseRestController.class);
    
    	List<Course> courses = new ArrayList<>();
    
    	public CourseRestController() {
    		courses.add(new Course(1, "Computer Science"));
    		courses.add(new Course(2, "Mathematics"));
    		courses.add(new Course(3, "Physics"));
    	}
    
    	@RequestMapping(value = "/courses") // http://localhost:8090/courses
    	public List<Course> listAll() {
    		LOG.info("returning list of courses");
    		return courses;
    	}
    
    }  

    Step 3) Create application.yml file under src/main/resources

    spring:
      application:
        name: course-service
    
    server:
      port: 8090   

    Step 4) Launch CourseApplication

    Launch http://localhost:8090/courses in the browser. You will see below page with list of courses in the broswer.

    CircuitBreaker












    2) Create CourseClient Application

    Now create CourseClient Application enabled with Resilience4j Circuit Breaker. It means when CourseClient calls CourseService, and it is down, we will still get a response that can be gracefully handled.

    Step 1) Create pom.xml file with below dependencies

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
    </dependencies>
    	
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>       

    Step 2) Create CircuitBreakerCourseApplication, CourseController, CourseClientResilience4J classes

    import java.time.Duration;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.client.RestTemplateBuilder;
    import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
    import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
    import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
    import org.springframework.cloud.client.circuitbreaker.Customizer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
    import io.github.resilience4j.timelimiter.TimeLimiterConfig;
    
    @SpringBootApplication
    public class CircuitBreakerCourseApplication {
    
    	@Bean
    	public RestTemplate rest(RestTemplateBuilder builder) {
    		return builder.build();
    	}
    
    	// Default Configuration for Resilience4JCircuitBreakerFactory
    	@Bean
    	public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
    		return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                    .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build())
                    .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build());
    	}
        
        // Default Configuration for ReactiveResilience4JCircuitBreakerFactory
    	@Bean
    	public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultReactiveCustomizer() {
    	    return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
    	            .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
    	            .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build()).build());
    	}
    	
    	public static void main(String[] args) {
    		SpringApplication.run(CircuitBreakerCourseApplication.class, args);
    	}
    
    } 
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class CourseController {
    	
    	@Autowired
    	private CourseClientResilience4J courseClient;
    	
    	@RequestMapping("/allCourses") // http://localhost:8080/allCourses
    	public String getCourseList() {
    		return courseClient.courseList();
    	}
    
    } 

    import java.net.URI;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreaker;
    import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    @Service
    public class CourseClientResilience4J {
    
    	private static final Logger LOG = LoggerFactory.getLogger(CourseClientResilience4J.class);
    	private final RestTemplate restTemplate;
    	private final Resilience4JCircuitBreaker circuitBreaker;
    
    	public CourseClientResilience4J(Resilience4JCircuitBreakerFactory circuitBreakerFactory,
    			RestTemplate restTemplate) {
    		this.restTemplate = restTemplate;
    		this.circuitBreaker = circuitBreakerFactory.create("courses");
    	}
    
    	public String courseList() {
    		URI uri = URI.create("http://localhost:8090/courses");
    		return circuitBreaker.run(() -> this.restTemplate.getForObject(uri, String.class),
                throwable -> {
    			    LOG.error("error while calling course service", throwable);
    			    return "{id:1, description: Computer Science}";
    		});
    	}
    
    }

    Step 3) Run CircuitBreakerCourseApplication

    Launch http://localhost:8080/allCourses in the browser. You will see below page with list of courses in the broswer.

    CircuitBreaker












    Step 4) Shutdown CourseServiceApplication

    Shutdown CourseServiceApplication and refresh http://localhost:8080/allCourses in the browser.

    Now circuit breaker will come into picture and will not send rqeuests to CourseServiceApplication. Instead it will return the data provided by the fallback mechanism.


    Maven Build








    3) Using ReactiveCircuitBreaker

    In this example we have used Resilience4JCircuitBreaker, but you can also use ReactiveCircuitBreaker in case we are using reactive data like Mono, Flux. Write CourseClientReactiveResilience4J class and then use it in CourseController class.

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
    import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    import org.springframework.web.reactive.function.client.WebClient;
    
    import reactor.core.publisher.Mono;
    
    @Service
    public class CourseClientReactiveResilience4J {
    
    	private static final Logger LOG = 
                LoggerFactory.getLogger(CourseClientReactiveResilience4J.class);
    	private final WebClient webClient;
    	private final ReactiveCircuitBreaker reactiveCircuitBreaker;
    
    	public CourseClientReactiveResilience4J(
                ReactiveResilience4JCircuitBreakerFactory circuitBreakerFactory, 
                RestTemplate restTemplate) {
            this.webClient = WebClient.builder().baseUrl("http://localhost:8090").build();
            this.reactiveCircuitBreaker = circuitBreakerFactory.create("courses");
        }
    
    	public Mono<String> courseList() {
    		return reactiveCircuitBreaker.run(webClient.get().
                    uri("/courses").retrieve().bodyToMono(String.class),
                    throwable -> {
                        LOG.error("error while calling course service", throwable);
                        return Mono.just("{id:1, description: Computer Science}");
                    });
    	}
    }
    

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import reactor.core.publisher.Mono;
    
    @RestController
    public class CourseController {
    	
    	@Autowired
    	private CourseClientReactiveResilience4J reactiveCourseClient;
    	
    	@RequestMapping("/allCoursesReactive") // http://localhost:8080/allCoursesReactive
    	public Mono<String> getCourseListReactive() {
    		return reactiveCourseClient.courseList();
    	}
    }






    References :

    Spring Cloud Circuit Breaker

    Comments

    Leave a Reply

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











    Share This