Skip to main content

7.5 Resilience & Fault Tolerance with Resilience4j

← Back to Chapter 7: Microservices & Spring Cloud

In distributed microservices, network timeouts and downstream outages are inevitable. Without fault tolerance, a single failing downstream service causes thread exhaustion across callers, triggering cascading system-wide failure. Resilience4j prevents this catastrophe.


1. The Circuit Breaker State Machine​

A Circuit Breaker operates in three distinct states:

┌──────────────────────┐
│ CLOSED │ (Normal operation; requests pass)
└──────────┬───────────┘
│ Failure Rate > Threshold (e.g. 50%)
▼
┌──────────────────────┐
│ OPEN │ (Fails FAST immediately; invokes Fallback)
└──────────┬───────────┘
│ Wait Duration expires (e.g. 10s)
▼
┌──────────────────────┐
│ HALF-OPEN │ (Permits trial requests to test downstream)
└──────────┬───────────┘
Success Rate │ │ Failure Rate
> Threshold ▼ ▼ > Threshold
[ CLOSED ] [ OPEN ]

2. Using @CircuitBreaker & Fallback Methods​

@Service
public class OrderProcessingService {

private static final Logger log = LoggerFactory.getLogger(OrderProcessingService.class);
private final PaymentServiceClient paymentClient;

public OrderProcessingService(PaymentServiceClient paymentClient) {
this.paymentClient = paymentClient;
}

@CircuitBreaker(name = "paymentService", fallbackMethod = "processPaymentFallback")
@Retry(name = "paymentService")
public PaymentResponse executePayment(PaymentRequest request) {
return paymentClient.processPayment(request);
}

// Fallback method MUST have identical parameter list PLUS the Throwable at the end!
public PaymentResponse processPaymentFallback(PaymentRequest request, Throwable ex) {
log.warn("Payment service unavailable! Falling back to queued payment. Reason: {}", ex.getMessage());
return new PaymentResponse(
request.orderId(),
PaymentStatus.QUEUED_FOR_RETRY,
"Service degraded. Payment queued for asynchronous settlement."
);
}
}

3. Configuration in application.yml​

resilience4j:
circuitbreaker:
instances:
paymentService:
sliding-window-type: COUNT_BASED
sliding-window-size: 10
minimum-number-of-calls: 5
failure-rate-threshold: 50.0 # Open if 50% of last 10 calls fail
wait-duration-in-open-state: 10s
permitted-number-of-calls-in-half-open-state: 3
retry:
instances:
paymentService:
max-attempts: 3
wait-duration: 500ms
exponential-backoff-multiplier: 2