🚀 Introduction: Why Circuit Breaker Matters in Microservices?
In microservices architecture, failures in one service can impact multiple services. Common issues include:
✔ Network failures
✔ Service timeouts
✔ Slow response times
Without proper handling, these failures can lead to:
❌ Increased latency
❌ System-wide slowdowns
❌ Cascading failures across microservices
✅ Solution: The Circuit Breaker Pattern
The Circuit Breaker Pattern helps by:
1️⃣ Detecting service failures
2️⃣ Preventing unnecessary calls to failing services
3️⃣ Returning a fallback response instead of failing entirely
4️⃣ Automatically retrying after a cooldown period
1️⃣ Architecture of Our Microservices Example
We will build two microservices and implement the Circuit Breaker pattern using Spring Boot 3+, WebClient, and Resilience4j.
Microservices Involved:
✔ Order Service (order-service
) → Calls Payment Service
✔ Payment Service (payment-service
) → Fails randomly to simulate failures
📌 If payment-service
fails, order-service
should handle the failure gracefully using the Circuit Breaker.
2️⃣ Payment Service (Simulating Failures)
Step 1: Create payment-service
@RestController
@RequestMapping("/api/payments")
public class PaymentController {
@GetMapping("/{orderId}")
public ResponseEntity<String> processPayment(@PathVariable String orderId) {
// Simulating service failure randomly
if (new Random().nextInt(10) < 4) { // 40% failure rate
throw new RuntimeException("Payment Service is Down!");
}
return ResponseEntity.ok("Payment successful for Order ID: " + orderId);
}
}
📌 This service randomly fails 40% of the time to test Circuit Breaker behavior.
3️⃣ Order Service with Circuit Breaker (Spring Boot 3+)
Step 1: Add Dependencies (Spring Boot 3+ & Resilience4j)
Update pom.xml
to use the latest Resilience4j dependency for Spring Boot 3+:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
✅ WebClient is used instead of RestTemplate
because RestTemplate
is deprecated in Spring Boot 3+.
Step 2: Configure WebClient in OrderService
@Configuration
public class WebClientConfig {
@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
📌 This config allows us to use WebClient for making HTTP calls.
Step 3: Implement Circuit Breaker in Order Service
@Service
public class OrderService {
private final WebClient.Builder webClientBuilder;
public OrderService(WebClient.Builder webClientBuilder) {
this.webClientBuilder = webClientBuilder;
}
@CircuitBreaker(name = "paymentService", fallbackMethod = "fallbackPayment")
public String placeOrder(String orderId) {
return webClientBuilder.build()
.get()
.uri("http://localhost:8081/api/payments/" + orderId) // Call Payment Service
.retrieve()
.bodyToMono(String.class)
.block();
}
public String fallbackPayment(String orderId, Throwable t) {
return "Fallback: Payment service is currently unavailable. Placing order without payment confirmation.";
}
}
📌 If the payment-service
is down, the fallbackPayment()
method is triggered instead.
Step 4: Create Order Controller
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping("/{orderId}")
public ResponseEntity<String> createOrder(@PathVariable String orderId) {
return ResponseEntity.ok(orderService.placeOrder(orderId));
}
}
✅ This API will attempt to process a payment and place an order.
4️⃣ Configuring Circuit Breaker Properties
Add the following properties in application.yml
for Circuit Breaker behavior tuning:
resilience4j:
circuitbreaker:
instances:
paymentService:
failureRateThreshold: 50 # Opens when 50% of calls fail
slowCallRateThreshold: 50
slowCallDurationThreshold: 2000ms # 2 seconds
permittedNumberOfCallsInHalfOpenState: 2
waitDurationInOpenState: 5000ms # 5 seconds
slidingWindowSize: 10
minimumNumberOfCalls: 5
📌 This configuration ensures that the circuit breaker opens if 50% of calls fail within 10 attempts.
5️⃣ Testing Circuit Breaker Using Postman
1️⃣ Case: Payment Service is Available
📌 Request:
POST http://localhost:8080/api/orders/123
📌 Response:
{
"message": "Payment successful for Order ID: 123"
}
✅ Everything works fine if the payment service is available.
2️⃣ Case: Payment Service Fails (Circuit Breaker Activated)
📌 Request:
POST http://localhost:8080/api/orders/456
📌 Response (Fallback Triggered):
{
"message": "Fallback: Payment service is currently unavailable. Placing order without payment confirmation."
}
✅ Instead of failing, the order is placed without payment confirmation.
6️⃣ Benefits of Circuit Breaker in Microservices
✅ Prevents cascading failures when a service goes down
✅ Provides fallback responses to improve user experience
✅ Automatically recovers after a cooldown period
✅ Improves system stability and resilience
7️⃣ Best Practices for Circuit Breaker in Microservices
✔ Set failure thresholds wisely to avoid false positives
✔ Implement fallback methods to ensure graceful degradation
✔ Monitor metrics using Prometheus or Grafana
✔ Combine with Retry Pattern to recover from temporary failures
🎯 Conclusion: Why Circuit Breaker is Essential for Microservices?
By implementing the Circuit Breaker Pattern, you can:
✅ Prevent service failures from cascading across the system
✅ Improve fault tolerance and resilience
✅ Ensure better user experience with fallbacks
🚀 Have you implemented Circuit Breaker in your microservices? Comment below!
🔗 Share this guide with developers to help them build resilient microservices! 🚀
Comments
Post a Comment
Leave Comment