Resilience4j Circuit Breakers in Spring Boot 3
Modern microservices demand resilience: when dependencies fail or overload, you must prevent cascading failures. Resilience4j offers modular support for key patterns—Circuit Breaker, Retry, Rate Limiter, Bulkhead—all designed to empower Spring Boot 3 apps with fault tolerance without bringing in heavyweight dependencies like Hystrix.
Setup for Spring Boot 3
Add these to your pom.xml:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-micrometer</artifactId> </dependency>
Metrics are enabled automatically via Actuator and Micrometer.
Patterns: Usage Examples
1. Circuit Breaker + Retry
application.yml:
resilience4j:
circuitbreaker:
configs:
default:
failureRateThreshold: 50
slidingWindowSize: 10
waitDurationInOpenState: 10s
instances:
backendService: {}
retry:
instances:
backendService:
maxAttempts: 3
waitDuration: 1s
exponentialBackoffMultiplier: 2.0
Service code:
@CircuitBreaker(name="backendService", fallbackMethod="cbFallback")
@Retry(name="backendService")
public String fetchData() {
return externalClient.getData();
}
public String cbFallback(Throwable ex) {
return "Service temporarily unavailable";
}
his retries with exponential backoff and prevents cascading failures.
2. Rate Limiter
application.yml:
resilience4j.ratelimiter:
instances:
apiLimiter:
limitForPeriod: 5
limitRefreshPeriod: 10s
timeoutDuration: 500ms
Controller:
@RateLimiter(name="apiLimiter", fallbackMethod="rateLimitFallback")
@GetMapping("/limited")
public String limited() {
return myService.callExternal();
}
public String rateLimitFallback(Throwable ex) {
return "Too many requests, try later.";
}
This ensures no more than 5 calls are allowed per 10 seconds.
3. Bulkhead
application.yml:
resilience4j.bulkhead:
instances:
bulkheadApi:
maxConcurrentCalls: 3
maxWaitDuration: 1ms
Endpoint:
@GetMapping("/bulkhead")
@Bulkhead(name="bulkheadApi", type=Bulkhead.Type.SEMAPHORE)
public String bulkheadCall() {
return externalClient.call();
}
@ExceptionHandler(BulkheadFullException.class)
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
public void handleBulkhead() {}
This limits concurrent calls and rejects excess ones, preventing overload.
Best Practices
| Pattern | Practice |
|---|---|
| Circuit Breaker | Set failure thresholds and half-open policies; centralize configs. |
| Retry | Use bounded, exponential backoff. Avoid retries without CB. |
| Rate Limiter | Control client or third-party calls to prevent resource exhaustion. |
| Bulkhead | Isolate resource pools using semaphores or threads. |
| Metrics | Monitor all patterns via Micrometer/Actuator dashboards. |
| Fallbacks | Provide meaningful fallback responses for each pattern. |
| Combine Wisely | Apply in layers: rate limiter → bulkhead → circuit breaker → retry. |
Developer Insights
From r/java:
“Retries should never ever be used in microservice landscapes between services without circuit breakers… retries alone will DDoS itself”
From r/java:
“Resilience4j is pretty nice with OpenFeign… we use Bucket4J for rate limiting”
From r/SpringBoot:
“Resilience4j is a more flexible option with retry, circuit breakers, and bulkhead patterns.”
These voices highlight that patterns must be combined smartly to avoid unintended failures.
Real-World Service Integration
Compose decorators with Resilience4j’s fluent API:
Supplier<String> supplier = () -> client.call();
Supplier<String> decorated = Decorators.ofSupplier(supplier)
.withCircuitBreaker(CircuitBreaker.ofDefaults("svc"))
.withRateLimiter(RateLimiter.ofDefaults("svc"))
.withBulkhead(Bulkhead.ofDefaults("svc"))
.withRetry(Retry.ofDefaults("svc"))
.decorate();
Try.ofSupplier(decorated)
.recover(Throwable.class, "fallback");
This provides layered protection: rate limiting, concurrency control, circuit breaker, and retries—all in one cohesive pipeline.
Further Resources
- Official Resilience4j docs: annotating patterns and decorators
- Spring Cloud CircuitBreaker with Resilience4j guide
- Enrico Homann’s fault-tolerance tutorial for combined patterns
- Medium article on combining retry, rate limiter, bulkhead with Resilience4j
Conclusion
Resilience4j brings fault-tolerance patterns together in a modular way for Spring Boot 3. By combining rate limiting, bulkhead isolation, circuit breaking, and retry, your microservices can withstand failures and avoid cascading downtime. Just remember: applying them coherently—with metrics, fallbacks, and proper governance—makes for robust, reliable systems.




