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