Resilience4j, a lightweight fault tolerance library designed for functional programming, has released version 2.0 featuring support for Java 17 and dependency upgrades to Kotlin, Spring Boot and Micronaut. This new version also removes the dependency on Vavr in order to become a more lightweight library.
Robert Winkler, solution architect at Deutsche Telekom AG and creator of Resilience4j explained the removal of Vavr on Twitter, writing:
I still love Vavr, but users of Resilience4j requested to have an even more lightweight library.
Vavr, a functional library for Java, provides immutable collections and supporting functions and control structures. The latest version, 0.10.4, was released July 2021. The library, formerly called Javaslang, was first released in 2013 before rebranding to Vavr in 2017.
Resilience4j 2.0.0 succeeds version 1.7.1, released in June 2021, and is the first major release since version 1.0.0 in September 2019.
The library now requires Java 17, the latest available LTS version, which allows users to run on Java 17 and use features such as Sealed Classes. There were also dependency upgrades to Kotlin 1.7.20, Spring Boot 2.7 and Micronaut 3.7.3.
Resilience4j offers several features such as the CircuitBreaker
which prevents calls to a service whenever the service isn't responding properly on time. This prevents the service from overloading. Consider the following example in which CircuitBreaker
may be implemented for a retrieveStudents()
method on a SchoolService
class:
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, schoolService::retrieveStudents);
String result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "Recovered from throwable").get();
Alternatively, the CircuitBreaker
may be implemented without a decorator:
String result = circuitBreaker
.executeSupplier(schoolService::retrieveStudents);
TimeLimiter
allows limiting the amount of time spent calling a service by specifying a timeout. For example, by using a CompletableFuture
to create a non-blocking solution:
TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
timeLimiter.executeCompletionStage(scheduler, () -> CompletableFuture.supplyAsync(schoolService::retrieveStudents))
.toCompletableFuture();
While TimeLimiter
restricts the call duration from the client, RateLimiter
restricts the number of calls per second from client(s). By default, the requests are limited to 50 calls per 500 ns:
CheckedRunnable restrictedCall = RateLimiter
.decorateCheckedRunnable(rateLimiter, schoolService::retrieveStudents);
Try.run(restrictedCall)
.andThenTry(restrictedCall)
.onFailure((RequestNotPermitted throwable) -> LOG.info("Please
wait"));
RateLimiter
also limits the total number of calls in a certain period and ThreadPoolBulkhead
limits the number of concurrent calls:
ThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()
.maxThreadPoolSize(10)
.coreThreadPoolSize(2)
.queueCapacity(20)
.build();
ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.of("name", config);
ThreadPoolBulkhead.executeSupplier(bulkhead,
schoolService::retrieveStudents);
Retry
is another feature which, by default, retries the call three times with 500ms between calls:
CheckedFunction0<Student> retryableSupplier = Retry
.decorateCheckedSupplier(retry, schoolService::retrieveStudents);
Try<String> result = Try.of(retryableSupplier)
.recover((throwable) -> "Recovered from throwable");
Spring Boot makes it even easier to use Resilience4j by providing annotations such as @CircuitBreaker
, @RateLimiter
, @Bulkhead
, @Retry
and @TimeLimiter
. The Getting Started Guide for Spring Boot 2 describes the options in more detail.
More information about Resilience4j may be found in the User Guide.