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

Micrometer

Getting started with resilience4j-micrometer

Resilience4j provides a module for Micrometer which supports most popular monitoring systems like InfluxDB or Prometheus.
The module expects that micrometer-core is already provided at runtime. Spring Reactor is not a transitive dependency.

repositories {
    jCenter()
}

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

CircuitBreaker Metrics

The following code snippet shows how to bind CircuitBreaker metrics to a MeterRegistry. It binds all CircuitBreaker instances at once and registers event consumers to dynamically bind newly created instances.

MeterRegistry meterRegistry = new SimpleMeterRegistry();
CircuitBreakerRegistry circuitBreakerRegistry =
  CircuitBreakerRegistry.ofDefaults();
CircuitBreaker foo = circuitBreakerRegistry
  .circuitBreaker("backendA");
CircuitBreaker boo = circuitBreakerRegistry
  .circuitBreaker("backendB");

TaggedCircuitBreakerMetrics
  .ofCircuitBreakerRegistry(circuitBreakerRegistry)
  .bindTo(meterRegistry)

The following metrics are exported:

Metric name
Type
Tags
Description

resilience4j
.circuitbreaker
.calls

Timer

name="backendA"

Total number of successful and failed calls

resilience4j
.circuitbreaker
.max.buffered.calls

Gauge

name="backendA"

The maximum number of buffered calls which can be stored in the current ring buffer

resilience4j
.circuitbreaker
.state

Gauge
0 - Not active
1 - Active

One of the following:

  • state="closed"
  • state="open"
  • state="half_open"
  • state="forced_open"
  • state="disabled"

name="backendA"

The states of the circuit breaker

resilience4j
.circuitbreaker
.failure.rate

Gauge

name="backendA"

The failure rate of the circuit breaker

resilience4j
.circuitbreaker
.buffered.calls

Gauge

One of the following:

  • kind="failed"
  • kind="successful"

name="backendA"

The number of buffered successful and failed calls stored in the ring buffer

resilience4
.circuitbreaker
.calls

Counter

kind="not_permitted"

name="backendA"

Total number of calls which failed but the exception was ignored

resilience4j
.circuitbreaker
.slow.call.rate

Gauge

name="backendA"

The slow call of the circuit breaker

Retry Metrics

The following code snippet shows how to bind Retry metrics to a MeterRegistry. It binds all Retry instances at once and registers event consumers to dynamically bind newly created instances

MeterRegistry meterRegistry = new SimpleMeterRegistry();
RetryRegistry retryRegistry = RetryRegistry.ofDefaults();
Retry retry = retryRegistry.retry("backendA");

// Register all retries at once
TaggedRetryMetrics
  .ofRetryRegistry(retryRegistry)
  .bindTo(meterRegistry);

The following metrics are exported:

Metric name
Type
Tags
Description

resilience4j
.retry
.calls

Gauge

One of the following:

  • kind="successful.without.retry"
  • kind="successful.with.retry"
  • kind="failed.with.retry"
  • kind="failed.without.retry"

name="backendA"

The number of calls by kind

Bulkhead Metrics

The following code snippet shows how to bind Bulkhead metrics to a MeterRegistry. It binds all Bulkhead instances at once and registers event consumers to dynamically bind newly created instances

MeterRegistry meterRegistry = new SimpleMeterRegistry();
BulkheadRegistry bulkheadRegistry = BulkheadRegistry.ofDefaults();
Bulkhead bulkhead = bulkheadRegistry.bulkhead("backendA");

// Register all retries at once
TaggedBulkheadMetrics
  .ofBulkheadRegistry(bulkheadRegistry)
  .bindTo(meterRegistry);

The following metrics are exported:

Metric name
Type
Tags
Description

resilience4j
.bulkhead
.available
.concurrent.calls

Gauge

name="backendA"

The number of available permissions

resilience4j
.bulkhead
.max.allowed
.concurrent.calls

Gauge

name="backendA"

The maximum number of available permissions

RateLimiter Metrics

The following code snippet shows how to bind RateLimiter metrics to a MeterRegistry. It binds all RateLimiter instances at once and registers event consumers to dynamically bind newly created instances

MeterRegistry meterRegistry = new SimpleMeterRegistry();
RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.ofDefaults();
RateLimiter rateLimiter = rateLimiterRegistry
  .rateLimiter("backendA");

// Register rate limiters at once
TaggedRateLimiterMetrics
  .ofRateLimiterRegistry(rateLimiterRegistry)
  .bindTo(meterRegistry);

The following metrics are exported:

Metric name
Type
Tags
Description

resilience4j.ratelimiter
.available.permissions

Gauge

name="backendA"

The number of available permissions

resilience4j.ratelimiter
.waiting.threads

Gauge

name="backendA"

The number of waiting threads

Prometheus

When you want to publish to Prometheus, you have to add the following dependency:

dependencies {
  compile "io.micrometer:micrometer-registry-prometheus"
}

The following metrics are exported per CircuitBreaker:

# HELP resilience4j_circuitbreaker_buffered_calls The number of buffered failed calls stored in the ring buffer
# TYPE resilience4j_circuitbreaker_buffered_calls gauge
resilience4j_circuitbreaker_buffered_calls{kind="failed",name="backendA",} 0.0
resilience4j_circuitbreaker_buffered_calls{kind="successful",name="backendA",} 0.0

# HELP resilience4j_circuitbreaker_calls_total Total number of not permitted calls
# TYPE resilience4j_circuitbreaker_calls_total counter
resilience4j_circuitbreaker_calls_total{kind="not_permitted",name="backendA",} 0.0

# HELP resilience4j_circuitbreaker_state The states of the circuit breaker
# TYPE resilience4j_circuitbreaker_state gauge
resilience4j_circuitbreaker_state{name="backendA",state="half_open",} 0.0
resilience4j_circuitbreaker_state{name="backendA",state="forced_open",} 0.0
resilience4j_circuitbreaker_state{name="backendA",state="disabled",} 0.0
resilience4j_circuitbreaker_state{name="backendA",state="closed",} 1.0
resilience4j_circuitbreaker_state{name="backendA",state="open",} 0.0
resilience4j_circuitbreaker_state{name="backendA",} 0.0

# HELP resilience4j_circuitbreaker_failure_rate The failure rate of the circuit breaker
# TYPE resilience4j_circuitbreaker_failure_rate gauge
resilience4j_circuitbreaker_failure_rate{name="backendA",} 20.0

# HELP resilience4j_circuitbreaker_max_buffered_calls The maximum number of buffered calls which can be stored in the ring buffer
# TYPE resilience4j_circuitbreaker_max_buffered_calls gauge
resilience4j_circuitbreaker_max_buffered_calls{name="backendA",} 5.0

# HELP resilience4j_circuitbreaker_calls_seconds_max Total duration of calls
# TYPE resilience4j_circuitbreaker_calls_seconds_max gauge
resilience4j_circuitbreaker_calls_seconds_max{kind="successful",name="backendA",} 0.0
resilience4j_circuitbreaker_calls_seconds_max{kind="failed",name="backendA",} 0.0
resilience4j_circuitbreaker_calls_seconds_max{kind="ignored",name="backendA",} 0.0

resilience4j_circuitbreaker_calls_seconds_sum{kind="ignored",name="backendA",} 0.0

# HELP resilience4j_circuitbreaker_calls_seconds Total number of successful calls
# TYPE resilience4j_circuitbreaker_calls_seconds histogram
resilience4j_circuitbreaker_calls_seconds_count{kind="successful",name="backendA",} 0.0
resilience4j_circuitbreaker_calls_seconds_sum{kind="successful",name="backendA",} 0.0

# HELP resilience4j_circuitbreaker_calls_seconds Total number of failed calls
# TYPE resilience4j_circuitbreaker_calls_seconds histogram
resilience4j_circuitbreaker_calls_seconds_count{kind="failed",name="backendA",} 0.0
resilience4j_circuitbreaker_calls_seconds_sum{kind="failed",name="backendA",} 0.0

The following metrics are exported per Bulkhead:

# HELP resilience4j_bulkhead_available_concurrent_calls The number of available permissions
# TYPE resilience4j_bulkhead_available_concurrent_calls gauge
resilience4j_bulkhead_available_concurrent_calls{name="backendA",} 10.0

# HELP resilience4j_bulkhead_max_allowed_concurrent_calls The maximum number available permissions
# TYPE resilience4j_bulkhead_max_allowed_concurrent_calls gauge
resilience4j_bulkhead_max_allowed_concurrent_calls{name="backendA",} 10.0

The following metrics are exported per Retry:

# HELP resilience4j_retry_calls The number of successful calls without a retry attempt
# TYPE resilience4j_retry_calls gauge
resilience4j_retry_calls{kind="failed_with_retry",name="backendA",} 0.0
resilience4j_retry_calls{kind="failed_without_retry",name="backendA",} 0.0
resilience4j_retry_calls{kind="successful_without_retry",name="backendA",} 0.0
resilience4j_retry_calls{kind="successful_with_retry",name="backendA",} 0.0

The following metrics are exported per RateLimiter:

# HELP resilience4j_ratelimiter_waiting_threads The number of waiting threads
# TYPE resilience4j_ratelimiter_waiting_threads gauge
resilience4j_ratelimiter_waiting_threads{name="backendA",} 0.0

# HELP resilience4j_ratelimiter_available_permissions The number of available permissions
# TYPE resilience4j_ratelimiter_available_permissions gauge
resilience4j_ratelimiter_available_permissions{name="backendA",} 50.0

Micrometer


Getting started with resilience4j-micrometer

Suggested Edits are limited on API Reference Pages

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