Resilience4j and dev.failsafe
(Failsafe) are both fault-tolerance libraries for Java, but they have key differences in their architecture, feature set, and intended use cases.
1. Design and Philosophy
-
Resilience4j : Built specifically for resilience in microservices, inspired by Netflix Hystrix. It provides various fault-tolerance mechanisms as independent modules.
-
Failsafe : A more lightweight and flexible general-purpose retry/fault-tolerance library with a functional and fluent API.
2. Features Comparison
Feature | Resilience4j | Failsafe |
---|---|---|
Retry | ✅ Yes (configurable backoff strategies) | ✅ Yes (exponential, jitter, etc.) |
Circuit Breaker | ✅ Yes (with half-open state) | ✅ Yes (adaptive circuit breaker) |
Rate Limiting | ✅ Yes (token-bucket based) | ❌ No |
Bulkhead (Concurrency Limits) | ✅ Yes (thread-based & semaphore-based) | ❌ No |
Time Limiting | ✅ Yes (Timeout feature) | ✅ Yes (execution timeouts) |
Fallback Handling | ✅ Yes | ✅ Yes |
Event Listeners / Metrics | ✅ Yes (with Micrometer integration) | ✅ Yes (custom event listeners) |
Integration with Spring Boot | ✅ Yes (Spring Boot starters available) | ❌ No native support, manual integration needed |
3. API Design
- Resilience4j : Uses a decorator pattern where each fault-tolerance feature is an independent module (e.g.,
Retry
,CircuitBreaker
, etc.). You explicitly decorate function calls.
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("myCircuitBreaker");
Supplier<String> decoratedSupplier = CircuitBreaker.decorateSupplier(circuitBreaker, () -> "Hello");
String result = Try.ofSupplier(decoratedSupplier).recover(throwable -> "Fallback").get();
- Failsafe : Provides a fluent API that chains policies together in a single execution block.
RetryPolicy<Object> retryPolicy = RetryPolicy.builder()
.handle(IOException.class)
.withBackoff(1, 10, ChronoUnit.SECONDS)
.build();
CircuitBreaker<Object> circuitBreaker = CircuitBreaker.builder()
.withFailureThreshold(3, 10)
.build();
Failsafe.with(circuitBreaker, retryPolicy)
.onSuccess(e -> System.out.println("Success!"))
.onFailure(e -> System.out.println("Failure!"))
.run(() -> doSomething());
4. Performance & Overhead
-
Resilience4j : Slightly more overhead because it provides additional features like rate limiting, bulkhead, and detailed metrics.
-
Failsafe : More lightweight and efficient for simple retry + circuit breaker needs.
5. Use Cases
-
Use Resilience4j when:
-
You need fine-grained control over resilience mechanisms.
-
You are working with a Spring Boot microservice.
-
You require built-in monitoring (Micrometer, Prometheus).
-
You need bulkhead or rate limiting.
-
-
Use Failsafe when:
-
You need a simple, lightweight fault-tolerance solution.
-
You want an easy-to-use API without external dependencies.
-
You prefer chaining multiple policies fluently.
-
You are building a non-Spring application or need a library-agnostic solution.
-
6. Integration & Ecosystem
-
Resilience4j : Well-integrated with Spring Boot (Spring Cloud Circuit Breaker, Micrometer, Actuator).
-
Failsafe : More suited for standalone Java applications or frameworks that do not rely on Spring.
Conclusion
If you're working on a Spring Boot microservice , Resilience4j is the better choice due to its rich feature set and built-in integration. However, if you want lightweight, simple, and flexible fault tolerance , especially outside of Spring Boot, dev.failsafe
is a great alternative.