Giter VIP home page Giter VIP logo

resilience4j's Introduction

Fault tolerance library designed for functional programming

1. Introduction

Resilience4j is a lightweight fault tolerance library designed for functional programming. Resilience4j provides higher-order functions (decorators) to enhance any functional interface, lambda expression or method reference with a Circuit Breaker, Rate Limiter, Retry or Bulkhead. You can stack more than one decorator on any functional interface, lambda expression or method reference. The advantage is that you have the choice to select the decorators you need and nothing else.

Resilience4j 2 requires Java 17.

// Create a CircuitBreaker with default configuration
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendService");

// Create a Retry with default configuration
// 3 retry attempts and a fixed time interval between retries of 500ms
Retry retry = Retry.ofDefaults("backendService");

// Create a Bulkhead with default configuration
Bulkhead bulkhead = Bulkhead.ofDefaults("backendService");

Supplier<String> supplier = () -> backendService
  .doSomething(param1, param2);

// Decorate your call to backendService.doSomething()
// with a Bulkhead, CircuitBreaker and Retry
// **note: you will need the resilience4j-all dependency for this
Supplier<String> decoratedSupplier = Decorators.ofSupplier(supplier)
  .withCircuitBreaker(circuitBreaker)
  .withBulkhead(bulkhead)
  .withRetry(retry)
  .decorate();

// Execute the decorated supplier and recover from any exception
String result = Try.ofSupplier(decoratedSupplier)
  .recover(throwable -> "Hello from Recovery").get();

// When you don't want to decorate your lambda expression,
// but just execute it and protect the call by a CircuitBreaker.
String result = circuitBreaker
  .executeSupplier(backendService::doSomething);

// You can also run the supplier asynchronously in a ThreadPoolBulkhead
 ThreadPoolBulkhead threadPoolBulkhead = ThreadPoolBulkhead
  .ofDefaults("backendService");

// The Scheduler is needed to schedule a timeout on a non-blocking CompletableFuture
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));

CompletableFuture<String> future = Decorators.ofSupplier(supplier)
    .withThreadPoolBulkhead(threadPoolBulkhead)
    .withTimeLimiter(timeLimiter, scheduler)
    .withCircuitBreaker(circuitBreaker)
    .withFallback(asList(TimeoutException.class, CallNotPermittedException.class, BulkheadFullException.class),
      throwable -> "Hello from Recovery")
    .get().toCompletableFuture();
ℹ️
With Resilience4j you don’t have to go all-in, you can pick what you need.

3. Overview

Resilience4j provides several core modules:

  • resilience4j-circuitbreaker: Circuit breaking

  • resilience4j-ratelimiter: Rate limiting

  • resilience4j-bulkhead: Bulkheading

  • resilience4j-retry: Automatic retrying (sync and async)

  • resilience4j-timelimiter: Timeout handling

  • resilience4j-cache: Result caching

There are also add-on modules for metrics, Feign, Kotlin, Spring, Ratpack, Vertx, RxJava2 and more.

ℹ️
Find out full list of modules in our User Guide.
💡
For core modules package or Decorators builder see resilience4j-all.

4. Resilience patterns

name how does it work? description links

Retry

repeats failed executions

Many faults are transient and may self-correct after a short delay.

overview, documentation, Spring

Circuit Breaker

temporary blocks possible failures

When a system is seriously struggling, failing fast is better than making clients wait.

overview, documentation, Feign, Spring

Rate Limiter

limits executions/period

Limit the rate of incoming requests.

overview, documentation, Feign, Spring

Time Limiter

limits duration of execution

Beyond a certain wait interval, a successful result is unlikely.

documentation, Spring

Bulkhead

limits concurrent executions

Resources are isolated into pools so that if one fails, the others will continue working.

overview, documentation, Spring

Cache

memorizes a successful result

Some proportion of requests may be similar.

documentation

Fallback

provides an alternative result for failures

Things will still fail - plan what you will do when that happens.

Try::recover, Spring, Feign

Above table is based on Polly: resilience policies.

ℹ️
To find more information about resilience patterns check Talks section. Find out more about components in our User Guide.

5. Spring Boot

Setup and usage in Spring Boot 2 is demonstrated here.

6. Usage examples

6.1. CircuitBreaker, Retry and Fallback

The following example shows how to decorate a lambda expression (Supplier) with a CircuitBreaker and how to retry the call at most 3 times when an exception occurs. You can configure the wait interval between retries and also configure a custom backoff algorithm.

The example uses Vavr’s Try Monad to recover from an exception and invoke another lambda expression as a fallback, when even all retries have failed.

// Simulates a Backend Service
public interface BackendService {
    String doSomething();
}

// Create a CircuitBreaker (use default configuration)
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
// Create a Retry with at most 3 retries and a fixed time interval between retries of 500ms
Retry retry = Retry.ofDefaults("backendName");

// Decorate your call to BackendService.doSomething() with a CircuitBreaker
Supplier<String> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, backendService::doSomething);

// Decorate your call with automatic retry
decoratedSupplier = Retry
    .decorateSupplier(retry, decoratedSupplier);

// Use of Vavr's Try to
// execute the decorated supplier and recover from any exception
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> "Hello from Recovery").get();

// When you don't want to decorate your lambda expression,
// but just execute it and protect the call by a CircuitBreaker.
String result = circuitBreaker.executeSupplier(backendService::doSomething);

6.1.1. CircuitBreaker and RxJava2

The following example shows how to decorate an Observable by using the custom RxJava operator.

CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
Observable.fromCallable(backendService::doSomething)
    .compose(CircuitBreakerOperator.of(circuitBreaker))
ℹ️
Resilience4j also provides RxJava operators for RateLimiter, Bulkhead, TimeLimiter and Retry. Find out more in our User Guide.

6.1.2. CircuitBreaker and Spring Reactor

The following example shows how to decorate a Mono by using the custom Reactor operator.

CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
Mono.fromCallable(backendService::doSomething)
    .transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
ℹ️
Resilience4j also provides Reactor operators for RateLimiter, Bulkhead, TimeLimiter and Retry. Find out more in our User Guide.

6.2. RateLimiter

The following example shows how to restrict the calling rate of some method to be not higher than 1 request/second.

// Create a custom RateLimiter configuration
RateLimiterConfig config = RateLimiterConfig.custom()
    .timeoutDuration(Duration.ofMillis(100))
    .limitRefreshPeriod(Duration.ofSeconds(1))
    .limitForPeriod(1)
    .build();
// Create a RateLimiter
RateLimiter rateLimiter = RateLimiter.of("backendName", config);

// Decorate your call to BackendService.doSomething()
Supplier<String> restrictedSupplier = RateLimiter
    .decorateSupplier(rateLimiter, backendService::doSomething);

// First call is successful
Try<String> firstTry = Try.ofSupplier(restrictedSupplier);
assertThat(firstTry.isSuccess()).isTrue();

// Second call fails, because the call was not permitted
Try<String> secondTry = Try.of(restrictedSupplier);
assertThat(secondTry.isFailure()).isTrue();
assertThat(secondTry.getCause()).isInstanceOf(RequestNotPermitted.class);

6.3. Bulkhead

There are two isolation strategies and bulkhead implementations.

6.3.1. SemaphoreBulkhead

The following example shows how to decorate a lambda expression with a Bulkhead. A Bulkhead can be used to limit the amount of parallel executions. This bulkhead abstraction should work well across a variety of threading and io models. It is based on a semaphore, and unlike Hystrix, does not provide "shadow" thread pool option.

// Create a custom Bulkhead configuration
BulkheadConfig config = BulkheadConfig.custom()
    .maxConcurrentCalls(150)
    .maxWaitDuration(100)
    .build();

Bulkhead bulkhead = Bulkhead.of("backendName", config);

Supplier<String> supplier = Bulkhead
    .decorateSupplier(bulkhead, backendService::doSomething);

6.3.2. ThreadPoolBulkhead

The following example shows how to use a lambda expression with a ThreadPoolBulkhead which uses a bounded queue and a fixed thread pool.

// Create a custom ThreadPoolBulkhead configuration
ThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()
    .maxThreadPoolSize(10)
    .coreThreadPoolSize(2)
    .queueCapacity(20)
    .build();

ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.of("backendName", config);

// Decorate or execute immediately a lambda expression with a ThreadPoolBulkhead.
Supplier<CompletionStage<String>> supplier = ThreadPoolBulkhead
    .decorateSupplier(bulkhead, backendService::doSomething);

CompletionStage<String> execution = bulkhead
    .executeSupplier(backendService::doSomething);

7. Consume emitted events

CircuitBreaker, RateLimiter, Cache, Bulkhead, TimeLimiter and Retry components emit a stream of events. It can be consumed for logging, assertions and any other purpose.

7.1. Examples

A CircuitBreakerEvent can be a state transition, a circuit breaker reset, a successful call, a recorded error or an ignored error. All events contains additional information like event creation time and processing duration of the call. If you want to consume events, you have to register an event consumer.

circuitBreaker.getEventPublisher()
    .onSuccess(event -> logger.info(...))
    .onError(event -> logger.info(...))
    .onIgnoredError(event -> logger.info(...))
    .onReset(event -> logger.info(...))
    .onStateTransition(event -> logger.info(...));
// Or if you want to register a consumer listening to all events, you can do:
circuitBreaker.getEventPublisher()
    .onEvent(event -> logger.info(...));

You can use RxJava or Spring Reactor Adapters to convert the EventPublisher into a Reactive Stream. The advantage of a Reactive Stream is that you can use RxJava’s observeOn operator to specify a different Scheduler that the CircuitBreaker will use to send notifications to its observers/consumers.

RxJava2Adapter.toFlowable(circuitBreaker.getEventPublisher())
    .filter(event -> event.getEventType() == Type.ERROR)
    .cast(CircuitBreakerOnErrorEvent.class)
    .subscribe(event -> logger.info(...))
ℹ️
You can also consume events from other components. Find out more in our User Guide.

8. Talks

0:34

Battle of the Circuit Breakers: Resilience4J vs Istio

Nicolas Frankel

GOTO Berlin

0:33

Battle of the Circuit Breakers: Istio vs. Hystrix/Resilience4J

Nicolas Frankel

JFuture

0:42

Resilience patterns in the post-Hystrix world

Tomasz Skowroński

Cloud Native Warsaw

0:52

Building Robust and Resilient Apps Using Spring Boot and Resilience4j

David Caron

SpringOne

0:22

Hystrix is dead, now what?

Tomasz Skowroński

DevoxxPL

9. Companies that use Resilience4j

  • Deutsche Telekom (In an application with over 400 million requests per day)

  • AOL (In an application with low latency requirements)

  • Netpulse (In a system with 40+ integrations)

  • wescale.de (In a B2B integration platform)

  • Topia (In an HR application built with microservices architecture)

  • Auto Trader Group plc (The largest Britain digital automotive marketplace)

  • PlayStation Network (A platform backend)

  • TUI InfoTec GmbH (Backend applications inside of reservation booking workflow streams for accommodations)

10. License

Copyright 2020 Robert Winkler, Bohdan Storozhuk, Mahmoud Romeh, Dan Maas and others

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

resilience4j's People

Contributors

celcius112 avatar cpilsworth avatar danielimre avatar dependabot[bot] avatar dlsrb6342 avatar drmaas avatar eddumelendez avatar emmanueltouzery avatar hexmind avatar kdombeck avatar krnsaurabh avatar laksnv avatar lespinsideg avatar maarek avatar madgnome avatar melochin avatar mgodave avatar mkopylec avatar patwlan avatar piyushmor avatar pulkitmehra avatar rlitto avatar robwin avatar romeh avatar storozhukbm avatar sullis avatar vijaycse avatar voievodin avatar walec51 avatar worldtiki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

resilience4j's Issues

Host ratpack integration module

Hi,

I created https://github.com/drmaas/ratpack-resilience4j, and was wondering if you're interested in hosting it here. I see you have a number of other integrations. It provides method interceptors for circuit breaking methods that return promises (and completion stage, observable, flowable, and normal values), and operators to circuit break and retry promises reactively.

Ratpack is a reactive, non-blocking web framework built on Netty that we've been using in production for over a year now, and have been happy with it. https://ratpack.io/

Dan

Log and listener for transitions

It would be great if CircuitBreaker could log the transitions that it makes. Having a listener for the transition changes would help a lot also, in order to hook specific actions for specific state changes.

Add execute methods to CircuitBreaker and Decorators builder.

Add execute defaults methods to the CircuitBreaker and execute methods to the Decorators builder. This makes it easier to decorate and call a function at once.

String result = circuitBreaker.executeSupplier(helloWorldService::returnHelloWorld);

or

 String result = Decorators.ofSupplier(() -> helloWorldService.returnHelloWorld())
    .withCircuitBreaker(CircuitBreaker.ofDefaults("id")
    .withRetry(Retry.ofDefaults("id"))
    .get();

Decorate a method which returns a CompletableFuture

In the docs the section on working with CompletableFuture looks like

Supplier<String> decoratedSupplier = CircuitBreaker
        .decorateSupplier(circuitBreaker, () -> "This can be any method which returns: 'Hello");

CompletableFuture<String> future = CompletableFuture.supplyAsync(decoratedSupplier)
        .thenApply(value -> value + " world'");

Doesn't seem like there is a straightforward to work with existing asynchronous code that may already return CompletableFuture, for example lets say I wanted to use a circuit-breaker on something that implements:

public interface Client {
    public CompletableFuture<String> get();
}

Would the recommended way to do this be:

  1. wrapping the client call in a Supplier
  2. implement a decorateSupplierOfCompletableFuture method that does Supplier.get() after the call to CircuitBreakerUtils.isCallPermitted(circuitBreaker)

???

Thanks.

try tests: how come the sleep time is zero?

i'm trying to improve the retry tests but it seems for them the waiting time between retries is zero although we call "ofDefaults" which should mean a sleep time of 500ms. I can't find the piece of magic which overrides this sleep time for the tests?

Fix CompletionStage handling support for Ratpack annotations

  • Retry
  • CircuitBreaker
  • RateLimiter

For each, since CompletionStage is not lazy, once invocation.proceed() is called, the future will execute, whether it is desired or not.

A better approach will be to switch on invocation.getMethod().getReturnType(), and then decide how to proceed for each return type.

Specifically for CompletionStage, it will be useful to only invoke the method if it is allowed to be invoked, based on the appropriate Retry, CircuitBreaker, or RateLimiter specified.

The other types can retain their logic as-is.

Reorder arguments in decorator methods

I have a few decorator methods that have various behaviours including rate limiting, timing, and of course, circuit breaking! I apply these in a chain, as per the decorator pattern.

CircuitBreaker.decorateSupplier has a type signature Supplier<T> decorateSupplier(Supplier<T> supplier, CircuitBreaker circuitBreaker), so chaining multiple decorator methods looks like:

RateLimiter.decorateSupplier(rateLimitConfig,
    CircuitBreaker.decorateSupplier(
        Stopwatch.decorateSupplier(stopwatchConfig,
            mySupplier()), circuitBreaker));

Notice that the CircuitBreaker instance is far from where it is applied in the chain, and looks out of place.

If CircuitBreaker.decorateSupplier had a type signature of Supplier<T> decorateSupplier(CircuitBreaker circuitBreaker, Supplier<T> supplier), then the same code would look like:

RateLimiter.decorateSupplier(rateLimitConfig,
    CircuitBreaker.decorateSupplier(circuitBreaker
        Stopwatch.decorateSupplier(stopwatchConfig,
            mySupplier()));

Now it's easier to associate the CircuitBreaker instance with the call to CircuitBreaker.decorateSupplier

Create a new Tracing decorator

API sketch:

Tracing trace = Tracing.of("traceName")
   .withTag("tagKey, "tagValue")
   .withTag("tagKey, "tagValue")
   .build();

Supplier<String> supplier = Tracing.decorateSupplier(trace, backendService::doSomething);


Flowable<TraceEvent> evenStream = trace.getEventStream();

A TraceEvent contains the trace ID, create time, the processing duration of the trace and a custom list of tags.

A client can consume the trace event stream and store events in InfluxDB, ElasticSearch.

We should have a look at the OpenTracing API (https://github.com/opentracing/opentracing-java)

@storozhukBM What do you thing about it?

Rename javaslang-curcuitbreaker

Hi Robert,
we already talked about it. Like the spring- prefix javaslang- indicates that a library belongs to the Javaslang organization. The same applies to package names.

I know that the renaming is a little bit of effort but there is already too much confusion.

It would be nice if this could be done until the next release.

Cheers,

Daniel

Create retry registry

It would be similar to the circuitbreaker registry. This would be useful for apps that use multiple retries at different places in the app, so that retries don't need to be manually injected or instantiated and passed in function arguments.

Cannot find artifacts in Maven Central

Hi, I am looking for resilience4j in Maven central but the only result I find is ratpack-resilience4j.

I used to have a dependency on javaslang-circuitbreaker. How can I use resilience4j from my Maven project?

And another question, is it planned to migrate Resilience4j to Vavr?

Thanks for this great project !

Ability to 'force' opening of a circuit breaker

It would be great if a developer can force the transition to OPEN to happen whenever desired.

The use-case I have is a failing backend service that is connected from several nodes. If a node detects a failure in this backend service, in order to minimize potential inconsistency with other nodes it's best if this node can advice all other nodes to move to OPEN on their own circuit-breaker instance, as soon as possible.

I understand the communication between nodes and such is fully beyond the scope of this project, but at minimum it would be needed:

  • to be able to force a transition to a given circuit-breaker
  • to be able to detect in the CircuitBreakerEventListener that the transition was 'forced'.

What do you think?

Why this code needs recovering?

import io.github.robwin.failsafe.FailSafe;
import io.github.robwin.retry.Retry;
import javaslang.control.Try;

public class Foobar {

    public static void main(String[] args) {

        Try.run(FailSafe.ofCheckedRunnable(() -> {
            System.out.println("Success");
        }).withRetry(Retry.ofDefaults())
                .decorate())
                .recover((throwable -> {
                    System.out.println("Recover me!");
                    return null;
                }));
        System.out.println("Finish");

    }
}

Execution result:

Success
Success
Success
Recover me!
Finish

Absolute number of failures instead of rate?

failureRateThreshold is a percentage. I'd like the circuit-breaker to be triggered immediately after the first failure... Could it be possible to have an absolute value for the failures, rater than a rate?

Modularize project into separate Gradle modules

at this point I use only the retry feature of circuitbreaker, but with 0.7 circuitbreaker now also pulls in for instance rxjava and other things which I don't need for such a small functionality as the retry feature.

Do you think maybe it would make sense to split the retry feature in its own artifact that the main circuitbreaker library would depend upon, so that it would be possible to depend only on that bit?

Zero allocation rate for CircuitBreaker

Hi team,

I've made small experimental branch (zero_allocation_rate_for_CB) with some performance improvements.
My changes basically give us zero allocation rate in case when CircuitBreaker has no event subscribers, with a sacrifice of CircuitBreaker API changes.
Benchmarks comparison

I'm not sure if this improvements are really worth CircuitBreaker API changes, so decided to discus it in this issue.

@RobWin, @goldobin, @cpilsworth what do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.