resilience4j

Resilience4j is a fault tolerance library for Java™

Resilience4j is a lightweight fault tolerance library inspired by Netflix Hystrix, but designed for functional programming. Lightweight, because the library only uses Vavr, which does not have any other external library dependencies. Netflix Hystrix, in contrast, has a compile dependency to Archaius which has many more external library dependencies such as Guava and Apache Commons Configuration.

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.

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

Supplier<String> decoratedSupplier = Decorators.ofSupplier(supplier)
  .withRetry(Retry.ofDefaults("name"))
  .withCircuitBreaker(CircuitBreaker.ofDefaults("name"))
  .withBulkhead(Bulkhead.ofDefaults("name"));  

String result = Try.ofSupplier(decoratedSupplier)
  .recover(throwable -> "Hello from Recovery").get();

With Resilience4j you don’t have to go all-in, you can pick what you need.

Get Started

Getting Started

Getting started with resilience4j-ratpack

Setup

Add the Ratpack Starter of Resilience4j to your compile dependency:

repositories {
    jCenter()
}

dependencies {
	compile "io.github.resilience4j:resilience4j-ratpack:${resilience4jVersion}"
}

Demo

Setup and usage in Ratpack is demonstrated into a demo.

Configuration

You can configure your CircuitBreaker, Retry, RateLimiter , Bulkead and Thread pool bulkhead instances in Ratpack’s application.yml config file.
For example

resilience4j:
    circuitbreaker:
        instances:
            backendA:
                ringBufferSizeInClosedState: 100
            backendB:
                ringBufferSizeInClosedState: 10
                ringBufferSizeInHalfOpenState: 3
                waitDurationInOpenState: PT50S
                failureRateThreshold: 50
                eventConsumerBufferSize: 10
                recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate

    retry:
        instances:
            backendA:
                maxRetryAttempts: 3
                waitDuration: PT10S
                enableExponentialBackoff: true
                exponentialBackoffMultiplier: 2
                retryExceptions:
                    - java.io.IOException
                ignoreExceptions:
                    - io.github.robwin.exception.BusinessException
            backendB:
                maxRetryAttempts: 3
                waitDuration: PT10S
                retryExceptions:
                    - java.io.IOException
                ignoreExceptions:
                    - io.github.robwin.exception.BusinessException

    bulkhead:
        instances:
            backendA:
                maxConcurrentCall: 10
            backendB:
                maxWaitDuration: PT0.01S
                maxConcurrentCall: 20

    threadpoolbulkhead:
      instances:
        backendC:
          threadPoolProperties:
            maxThreadPoolSize: 1
            coreThreadPoolSize: 1
            queueCapacity: 1

    ratelimiter:
        instances:
            backendA:
                limitForPeriod: 10
                limitRefreshPeriod: PT1S
                timeoutDuration: 0
                eventConsumerBufferSize: 100
            backendB:
                limitForPeriod: 6
                limitRefreshPeriod: PT0.5S
                timeoutDuration: PT3S

You can also override the default configuration, define shared configurations and overwrite them in Ratpack's application.yml config file.
For example:

resilience4j:
    circuitbreaker:
        configs:
            default:
                ringBufferSizeInClosedState: 100
                ringBufferSizeInHalfOpenState: 10
                waitDurationInOpenState: 10000
                failureRateThreshold: 60
                eventConsumerBufferSize: 10
            someShared:
                ringBufferSizeInClosedState: 50
                ringBufferSizeInHalfOpenState: 10
        instances:
            backendA:
                baseConfig: default
                waitDurationInOpenState: 5000
            backendB:
                baseConfig: someShared

Annotations

The Ratpack library provides annotations and AOP Aspects which are auto-configured.
RateLimiter, Retry, CircuitBreaker and Bulkhead annotations support synchronous return types, asynchronous types like CompletableFuture, and reactive types like Raptack's Promise and Spring Reactor's Flux and Mono.

Bulkhead annotation has now type attribute the define which bulkhead implementation will be used , by default it is semaphore but if you can switch to thread pool type by setting the type attribute in the annotation:

 @Bulkhead(name = BACKEND, type = Bulkhead.Type.THREADPOOL)
 public CompletableFuture<String> doSomethingAsync() throws InterruptedException {
        Thread.sleep(500);
        return CompletableFuture.completedFuture("Test");
    }

An example of all resilience4j supported AOP aspects:

@CircuitBreaker(name = BACKEND, fallbackMethod = "fallback")
@RateLimiter(name = BACKEND)
@Bulkhead(name = BACKEND)
@Retry(name = BACKEND, fallbackMethod = "fallback")
public Promise<String> method(String param1) {
   return Promise.error(new NumberFormatException());
 }

private Promise<String> fallback(String param1, IllegalArgumentException e) {
  return Promise.just("test");
}

private Promise<String> fallback(String param1, RuntimeException e) {
  return Promise.just("test");
}

It's important to remember that a fallback method should be placed in the same class and must have the same method signature (and an optional exception parameter).

If there are multiple fallbackMethod methods, the method that has the most closest match will be invoked, for example:

If you try to recover from NumberFormatException, the method with signature String fallback(String parameter, IllegalArgumentException exception)} will be invoked.

You can define one global fallback method with an exception parameter only if multiple methods has the same return type and you want to define the same fallback method for them once and for all.

Events Endpoint

The emitted CircuitBreaker, Retry, RateLimiter and Bulkhead events are stored in a separate circular event consumer buffers. The size of an event consumer buffer can be configured in the application.yml file (eventConsumerBufferSize).

The endpoint /circuitbreaker/states lists the state for of all CircuitBreaker instances. The endpoint /circuitbreaker/events lists the event list of all CircuitBreaker instances. The events endpoint is also available for Retry, RateLimiter and Bulkhead.
For example:

{
"circuitBreakerEvents":[
  {
    "circuitBreakerName": "backendA",
    "type": "ERROR",
    "creationTime": "2019-01-10T15:39:17.117-05:00[America/Chicago]",
    "errorMessage": "java.io.IOException: 500 This is a remote exception",
    "durationInMs": 0
  },
  {
    "circuitBreakerName": "backendA",
    "type": "SUCCESS",
    "creationTime": "2019-01-10T15:39:20.518-05:00[America/Chicago]",
    "durationInMs": 0
  },
  {
    "circuitBreakerName": "backendB",
    "type": "ERROR",
    "creationTime": "2019-01-10T15:41:31.159-05:00[America/Chicago]",
    "errorMessage": "java.io.IOException: 500 This is a remote exception",
    "durationInMs": 0
  },
  {
    "circuitBreakerName": "backendB",
    "type": "SUCCESS",
    "creationTime": "2019-01-10T15:41:33.526-05:00[America/Chicago]",
    "durationInMs": 0
  }
]
}

Getting Started


Getting started with resilience4j-ratpack

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.