Circuit Breaker in Spring Boot (Spring Cloud Circuit Breaker + Resilience4j)

  • 4.2/5
  • 821
  • Oct 30, 2024

What is circuit breaker pattern in microservices?

The circuit breaker pattern in microservices is a design pattern that helps prevent cascading failures in distributed systems by stopping or breaking the connection to a failing service or component after a threshold of failures is reached.

How It Works?

The circuit breaker monitors the number of failures or error rates over time and has three main states:

Closed: Requests are routed normally. The circuit breaker counts the number of recent failures. If these failures exceed a certain threshold within a defined window, the breaker switches to the Open state.

Open: Requests to the failing service are stopped immediately. Instead of making a call that’s likely to fail, the circuit breaker immediately returns an error or executes a fallback (alternative response). After a cooldown period, it moves to the Half-Open state.

Half-Open: A limited number of requests are allowed through to test if the service has recovered. If requests succeed, the circuit breaker resets to Closed; otherwise, it returns to Open.

What is Spring Cloud Circuit Breaker?

Spring Cloud Circuit Breaker is a library that provides an easy-to-use abstraction layer for implementing circuit breakers in Spring Boot applications, offering seamless integration with popular resilience libraries like Resilience4j and Spring Retry.

The following starters are available with the Spring Cloud BOM:

1) Resilience4j: org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j

2) Reactive Resilience4j: org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j

3) Spring Retry: org.springframework.cloud:spring-cloud-starter-circuitbreaker-spring-retry

In this article, we implement a circuit breaker with Resilience4j using org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j.

How to Implement Spring Cloud Circuit Breaker with Resilience4j?

Usecase

Imagine a microservices-based e-commerce application where an order-service relies on an inventory-service. If the "inventory-service" becomes slow or fails completely, the circuit breaker in "order-service" will "open" after several failed requests, stopping further requests to "inventory-service".

The "order-service" can then provide a fallback response (like 'inventory data is currently unavailable') to prevent impacting the end-user experience.

Implementation

inventory-service

This is a simple Spring Boot web application with only one endpoint, so there is no need to explain it here.

The source code for this application can be found here: Github.

order-service

Now, let's implement Spring Cloud Circuit Breaker using Resilience4j in the order-service, which calls inventory-service with a count-based circuit breaker.

1) Use Spring Initializr (Web Interface)

1.1) Open Spring Initializr in your browser.

1.2) Choose either Gradle - Groovy or Gradle - Kotlin as the build tool, based on your preferred language.

1.3) Select dependencies for your project, including Spring Web, Spring Boot Actuator, Resilience4J, and any other required dependencies.

1.4) Click Generate to download the project as a ZIP file.

1.5) Unzip the downloaded file, and open it in your preferred IDE, such as IntelliJ IDEA or VS Code.

2) Add Dependencies

Add the necessary dependencies to your build.gradle file. The final configuration should look something like this:

The spring-boot-starter-web dependency is used for building REST APIs. The spring-boot-starter-actuator dependency enables monitoring and management endpoints. The optional Lombok dependencies help reduce boilerplate code. The optional spring-boot-devtools dependency provides hot reloading to enhance development productivity.

3) Configure Properties

In your application.yml, add the following configurations for the inventory-service URL, Resilience4j circuit breaker, Swagger UI, and Actuator to expose the circuit breaker health endpoint.

4) Order Model

The Order model represents an order in the order-service. It includes basic fields like orderId, itemId, itemName, and quantity.

5) InventoryResponse Model

The InventoryResponse model represents the response from the inventory-service, containing fields for product availability status and possibly additional details.

6) Create InventoryServiceClient

Define a RestClient that will make a REST call to the inventory-service. Use the @CircuitBreaker annotation provided by Spring Cloud Circuit Breaker to apply the circuit breaker to the method.

The @CircuitBreaker annotation applies the circuit breaker to the getInventoryItem method.

The fallback method is called when the circuit breaker is open or the call fails.

7) Register RestTemplate Bean

Ensure a RestTemplate bean is available for dependency injection in your InventoryClient:

8) Use InventoryClient in the OrderController

Now, inject InventoryClient in OrderController and use it to call the inventory-service.

9) Run the Application

Start your Spring Boot application. After starting, the Swagger UI should be accessible at: http://localhost:8080/swagger-ui.html

10) Verify Circuit Breaker Behavior

Using Spring Boot Actuator, you can view circuit breaker metrics at the /actuator/circuitbreakers endpoint.

Trigger a few failed responses by having the inventory-service throw a RuntimeException or by shutting down the service. Once the configured failure threshold is reached, the circuit breaker will open, causing subsequent calls to return the fallback response.

After enough time has passed (e.g., 60 seconds, as per your configuration), the circuit breaker transitions to the half-open state.

As we have set the logging level for "io.github.resilience4j.circuitbreaker" to DEBUG, this will allow us to see the following informative logs in the application logs.

2024-10-28T01:16:15.470+05:30 DEBUG 6115 --- [order-service] [io-8080-exec-10] i.g.r.c.i.CircuitBreakerStateMachine     : CircuitBreaker 'inventory-circuit-breaker' recorded an exception as failure:
.
.
.
.
2024-10-28T01:16:15.923+05:30 DEBUG 6115 --- [order-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine     : Event ERROR published: 2024-10-28T01:16:15.923560+05:30[Asia/Kolkata]: CircuitBreaker 'inventory-circuit-breaker' recorded an error: 'org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : "{"timestamp":"2024-10-27T19:46:15.920+00:00","status":500,"error":"Internal Server Error","path":"/inventory/dummyItemId"}"'. Elapsed time: 7 ms
2024-10-28T01:16:15.924+05:30 DEBUG 6115 --- [order-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine     : Event FAILURE_RATE_EXCEEDED published: 2024-10-28T01:16:15.924930+05:30[Asia/Kolkata]: CircuitBreaker 'inventory-circuit-breaker' exceeded failure rate threshold. Current failure rate: 100.0
2024-10-28T01:16:15.930+05:30 DEBUG 6115 --- [order-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine     : Event STATE_TRANSITION published: 2024-10-28T01:16:15.930455+05:30[Asia/Kolkata]: CircuitBreaker 'inventory-circuit-breaker' changed state from CLOSED to OPEN
.
.
.
2024-10-28T01:16:20.939+05:30 DEBUG 6115 --- [order-service] [ransitionThread] i.g.r.c.i.CircuitBreakerStateMachine     : Event STATE_TRANSITION published: 2024-10-28T01:16:20.938948+05:30[Asia/Kolkata]: CircuitBreaker 'inventory-circuit-breaker' changed state from OPEN to HALF_OPEN

Unit Testing Circuit Breaker

This test class, InventoryClientTest, verifies the behavior of the InventoryClient class in different circuit breaker states:

Source code: GitHub

Index
How to Implement PostgreSQL Full-Text Search with Spring Boot

15 min

Spring's transaction management with the @Transactional annotation

9 min

Spring Boot Rest APIs with PostgreSQL (Spring Boot + Rest APIs)

15 min

Caching in Spring Boot (@Cacheable, @CacheEvict & @CachePut)

21 min

Declarative REST Client in Spring Boot (Spring 6 HTTP Interface)

13 min

Circuit Breaker in Spring Boot (Spring Cloud Circuit Breaker + Resilience4j)

12 min

Handling Concurrent Service Calls in a Spring Boot Application: Asynchronous vs. Reactive Approaches

11 min

Profiling a Spring Boot application with Pyroscope

7 min

Service discovery in Spring Boot (Spring Cloud + Netflix Eureka)

9 min

Dockerize Spring Boot app and Push image to DockerHub (Spring Boot + DockerHub)

4 min

Creating a Jenkins Pipeline for Spring Boot application

2 min

Monitoring Microservices (Spring Boot + Micrometer + Prometheus + Grafana)

7 min

Edge Server Pattern in Microservices (Spring Cloud Gateway)

7 min

Circuit Breaker Pattern in Microservices (Spring BOOT + Resilience4j)

4 min

Spring Cloud config server setup with Git

8 min

Distributed Tracing in Microservices (Spring Cloud Sleuth + Zipkin)

9 min

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

24 min

Deploying Spring Boot microservices on Kubernetes Cluster

12 min

Reactive programming in Java with Project Reactor

50 min

Spring Reactive with PostgreSQL (Spring Boot WebFlux + PostgreSQL)

13 min

Spring Reactive, Thymeleaf Hello World (Spring Webflux + Thymeleaf + JS/CSS)

9 min

Problem JSON (application/problem+json) in Spring WebFlux

15 min

Spring Boot Login/Logout (Spring Security + MySql + Thymeleaf)

21 min

Securing Server-to-Server Communication with "Spring Boot" & "OAuth 2"

18 min

Integrating Elasticsearch with a Spring Boot and PostgreSQL application

16 min

Sending Emails in Spring Boot via SMTP

7 min

How to create a basic Spring 6 project using Maven

5 min

Spring Boot, Thymeleaf Hello World (Spring Boot + Thymeleaf + JS/CSS)

9 min