Spring Boot Circuit Breaker Example with Resilience4j: Step-by-Step Guide
How to Implement and Test Circuit Breaker Pattern in Spring Boot Using Resilience4j — Includes Tests for Success and Failure
When developing an application, particularly one based on microservices, it’s common to encounter issues during real-time execution. These might include slow response times, network failures, REST call failures, or issues arising from a high volume of requests. To handle such potential faults, it’s essential to implement a fault tolerance mechanism within the application. Resilience4j is a library that can be used to achieve this.
Resilience4j is a lightweight, easy-to-use fault tolerance library inspired by Netflix Hystrix but specifically designed for Java 8 and functional programming. This article will focus on how to implement fault tolerance in microservices using Resilience4j.
What is Fault Tolerance in Microservices?
Fault tolerance in microservices refers to the system’s ability to continue functioning even when one or more of its components fail. Microservices architectures often consist of many small, independent services that communicate with each other over a network, making them more prone to failures. Ensuring fault tolerance helps maintain availability and reliability despite these failures.
Several patterns help achieve fault tolerance in microservices:
- Circuit Breaker Pattern: Protects services from repeated failure by “opening the circuit” when failures exceed a threshold, thus preventing further calls to the failing service for a while.
- Retry Pattern: Automatically retries failed requests in case the failure was transient.
- Fallback Pattern: Provides alternative methods or static data when a service fails or is unavailable.
- Bulkhead Pattern: Isolates different parts of the system into separate pools, preventing one service’s failure from affecting others.
- Timeouts: Limits the time a service waits for a response, preventing long delays from unresponsive services.
Importance of Fault Tolerance:
- Minimizes Downtime: Even when services fail, the system remains partially operational, minimizing the impact on users.
- Improves User Experience: Ensures the application continues to serve requests, even if some functionality is degraded.
- Enhances Scalability: With proper fault tolerance, services can handle dynamic changes in load and fail gracefully.
Here’s a complete example of the Circuit Breaker Pattern using Resilience4j with Spring Boot, including a diagram, use case scenario, input/output.
1. Use Case Scenario
In this example, the Student Service fetches course details from the Course Service. The Course Service might become unavailable due to network issues or downtime. Using the Circuit Breaker Pattern ensures that if the Course Service fails too many times within a short period, the calls to that service will be automatically blocked (open circuit) for a while before allowing them again (half-open, then closed state).
2. Project Setup
Ensure you have the following dependencies in your pom.xml:
<dependencies>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>3. Application Configuration
application.yml
resilience4j.circuitbreaker:
instances:
courseService:
registerHealthIndicator: true
slidingWindowSize: 5
minimumNumberOfCalls: 3
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3This configuration states:
- The circuit breaker will be triggered after 3 failures.
- 50% failure rate will open the circuit.
- The circuit remains open for 10 seconds before going into the half-open state.
1. resilience4j.circuitbreaker.instances.courseService :
This part defines the circuit breaker instance for a specific service, in this case, courseService. Resilience4j allows you to create different circuit breakers for different services (or parts of your application).
Property Explanations:
2. registerHealthIndicator: true
- This property indicates whether the circuit breaker will be registered as a health indicator.
- When set to
true, it allows the circuit breaker to expose its health status, which can be monitored through Spring Boot Actuator. This is useful for detecting whether the circuit is open, half-open, or closed.
3. slidingWindowSize: 5
- This defines the size of the sliding window for measuring the failure rate of requests. In this case, it tracks the last 5 requests to decide whether the failure rate has exceeded the threshold.
- The sliding window allows the circuit breaker to evaluate recent calls within this window size. If the failure rate within these calls exceeds the threshold, the circuit breaker will open.
4. minimumNumberOfCalls: 3
- This specifies the minimum number of requests that must be made before the circuit breaker starts evaluating the failure rate. In this case, it waits for at least 3 calls before deciding whether to open the circuit.
- Until this minimum number is met, the circuit breaker will not be triggered, even if there are failures.
5. failureRateThreshold: 50
- The failure rate threshold is set to 50%, meaning that if 50% or more of the requests within the sliding window (last 5 requests) fail, the circuit breaker will open.
- For example, if 2 out of 5 calls fail, the failure rate is 40%, so the circuit breaker remains closed. But if 3 out of 5 fail, the failure rate is 60%, and the circuit will open.
6. waitDurationInOpenState: 10s
- This defines how long the circuit breaker will stay open before it transitions to the half-open state. In this case, the circuit remains open for 10 seconds.
- When the circuit is open, all requests will automatically fail, and no further attempts will be made to call the failing service. After 10 seconds, it moves to the half-open state, where it tests the service again.
7. permittedNumberOfCallsInHalfOpenState: 3
- When the circuit is in the half-open state, this property defines how many calls are allowed to pass through to test if the service is back to normal. In this case, 3 calls are allowed.
- If these 3 calls succeed, the circuit will close, and normal traffic will resume. If they fail, the circuit will open again for another 10 seconds.
4. Service Layer Implementation
CourseService.java
package com.example.resilience4jdemo.service;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpServerErrorException;
@Service
public class CourseService {
private final RestTemplate restTemplate = new RestTemplate();
@CircuitBreaker(name = "courseService", fallbackMethod = "fallbackCourseDetails")
public String getCourseDetails(String studentId) {
String url = "http://localhost:8081/course/" + studentId;
return restTemplate.getForObject(url, String.class);
}
public String fallbackCourseDetails(String studentId, Throwable t) {
return "Fallback: Course service is currently unavailable for student " + studentId;
}
}1. @CircuitBreaker Annotation
- This annotation is used to mark a method for which the circuit breaker functionality should be applied.
2. name Attribute
name = "courseService"- This specifies the name of the circuit breaker instance. In this case, the circuit breaker is named
"courseService". - The name corresponds to the configuration defined in your
application.ymlorapplication.propertiesfile. It helps to identify which circuit breaker configuration to apply.
3. fallbackMethod Attribute
fallbackMethod = "fallbackCourseDetails"- This specifies the name of the method to be called if the circuit breaker is open or if the annotated method fails.
- The fallback method should have the same parameters as the annotated method, with an additional
Throwableparameter for capturing exceptions if needed.
StudentService.java
package com.example.resilience4jdemo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
@Autowired
private CourseService courseService;
public String getStudentCourseDetails(String studentId) {
return courseService.getCourseDetails(studentId);
}
}5. Controller Layer
StudentController.java
package com.example.resilience4jdemo.controller;
import com.example.resilience4jdemo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping("/student/{id}/course")
public String getStudentCourse(@PathVariable String id) {
return studentService.getStudentCourseDetails(id);
}
}.
+--------------------+ +--------------------+
| | | |
| Student Service |<------>+ Course Service |
| | | |
+--------------------+ +--------------------+
|
|
v
+---------------------+
| Resilience4j |
| Circuit Breaker |
| (courseService) |
+---------------------+If you want to create a dummy response for the URL http://localhost:8081/course/{studentId}, here's how you can implement it in a Spring Boot service:
package com.example.courseservice.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CourseController {
@GetMapping("/course/{studentId}")
public String getCourseDetails(@PathVariable String studentId) {
// Dummy response
return "{ \"courseName\": \"Computer Science\", \"studentId\": \"" + studentId + "\", \"duration\": \"4 years\" }";
}
}You can test the service using Postman or curl to ensure it returns the response:
- Request URL:
http://localhost:8081/course/123 - Method:
GET - Expected Response:
{
"courseName": "Computer Science",
"studentId": "123",
"duration": "4 years"
}6. Testing the Circuit Breaker
To test both success and failure scenarios using Postman, follow the steps below:
1. Start both services:
- Student Service on port
8080. - Course Service on port
8081.
2. Success Scenario (Course Service is UP)
2.1 Request
- Method:
GET - URL:
http://localhost:8080/student/1/course - Headers: None
2.2 Expected Response
When the Course Service is running and the student ID exists, you’ll get a normal response from the Course Service. The response might look like:
{
"courseName": "Computer Science",
"duration": "4 years"
}This verifies that the Student Service successfully communicates with the Course Service.
3. Failure Scenario (Course Service is DOWN)
3.1 Stop the Course Service
Stop the Course Service running on port 8081.
3.2 Request
Make the same request as before:
- Method:
GET - URL:
http://localhost:8080/student/1/course - Headers: None
3.3 Expected Response
Once the Course Service is down and the circuit breaker is triggered (after multiple failures based on your slidingWindowSize configuration), the fallback method will respond with:
{
"message": "Fallback: Course service is currently unavailable for student 1"
}This demonstrates the Circuit Breaker Pattern in action. After a certain number of failures, the circuit breaker will open, and the fallback method will be called, protecting the system from further stress.
4. Simulating Circuit Breaker States
Circuit Breaker states:
- Closed: Initially, all requests go through to the Course Service.
- Open: After the threshold is reached (e.g., 50% failure rate in the last 3 attempts), the circuit breaker opens, and the fallback is triggered immediately.
- Half-open: After a waiting period (
waitDurationInOpenState), the circuit breaker allows some requests to pass through to test if the service is back.
To observe this behavior:
- Stop the Course Service, make several requests until the circuit breaker opens.
- Restart the Course Service after the wait duration (e.g., 10 seconds), and observe the half-open state where some requests pass through to the Course Service before the circuit returns to the closed state.
Postman History and Results:
- Success: Normal response from the Course Service.
- Failure: Fallback response with “Fallback: Course service is currently unavailable”.
This will show both the success and failure paths handled by the circuit breaker.
👏 If you found my articles useful, please consider giving it claps and sharing it with your friends and colleagues.
To read other topics
- Spring Boot Retry Pattern Example with Resilience4j: Step-by-Step Guide
- Mastering Transaction Propagation and Isolation in Spring Boot
- @Formula Annotation in Spring Boot
- One To One mapping in Spring Boot JPA
- One To Many mapping in Spring Boot JPA
- SOLID Principles in Java
- Java 8 Interview Questions and Answer
- Java String Interview Questions and answer
- Kafka Interview Questions and Answers
- Optional in Java 8
- Global exception handling in spring boot
- Pessimistic Locking in JPA with Spring Boot
- Optimistic Locking in JPA with Spring Boot
- Design Pattern in java
- Generic ApiResponse and Global Exception Handling in Spring Boot
- Garbage Collection in Java
- JVM Architecture
- How the JIT Compiler Enhances Java Performance: An In-Depth Explanation
- Git and GitHub Integration in IntelliJ IDEA





