Getting Started
Getting started with resilience4j-spring-boot2 or resilience4j-spring-boot3
Setup
Add the Spring Boot Starter of Resilience4j to your compile dependency.
The module expects that org.springframework.boot:spring-boot-starter-actuator
and org.springframework.boot:spring-boot-starter-aop
are already provided at runtime. If you are using webflux with Spring Boot 2 or Spring Boot 3, you also need io.github.resilience4j:resilience4j-reactor
dependencies {
implementation "io.github.resilience4j:resilience4j-spring-boot3:${resilience4jVersion}"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "org.springframework.boot:spring-boot-starter-aop"
}
Demo
Setup and usage in Spring Boot 2 is demonstrated in a demo.
Setup and usage in Spring Boot 3 is demonstrated in a demo.
Configuration
You can configure your CircuitBreaker, Retry, RateLimiter, Bulkhead, Thread pool bulkhead and TimeLimiter instances in Spring Boot’s application.yml
config file.
For example
resilience4j.circuitbreaker
instances
backendA
registerHealthIndicatortrue
slidingWindowSize100
backendB
registerHealthIndicatortrue
slidingWindowSize10
permittedNumberOfCallsInHalfOpenState3
slidingWindowType TIME_BASED
minimumNumberOfCalls20
waitDurationInOpenState 50s
failureRateThreshold50
eventConsumerBufferSize10
recordFailurePredicate io.github.robwin.exception.RecordFailurePredicate
resilience4j.retry
instances
backendA
maxAttempts3
waitDuration 10s
enableExponentialBackofftrue
exponentialBackoffMultiplier2
retryExceptions
org.springframework.web.client.HttpServerErrorException
java.io.IOException
ignoreExceptions
io.github.robwin.exception.BusinessException
backendB
maxAttempts3
waitDuration 10s
retryExceptions
org.springframework.web.client.HttpServerErrorException
java.io.IOException
ignoreExceptions
io.github.robwin.exception.BusinessException
resilience4j.bulkhead
instances
backendA
maxConcurrentCalls10
backendB
maxWaitDuration 10ms
maxConcurrentCalls20
resilience4j.thread-pool-bulkhead
instances
backendC
maxThreadPoolSize1
coreThreadPoolSize1
queueCapacity1
writableStackTraceEnabledtrue
resilience4j.ratelimiter
instances
backendA
limitForPeriod10
limitRefreshPeriod 1s
timeoutDuration0
registerHealthIndicatortrue
eventConsumerBufferSize100
backendB
limitForPeriod6
limitRefreshPeriod 500ms
timeoutDuration 3s
resilience4j.timelimiter
instances
backendA
timeoutDuration 2s
cancelRunningFuturetrue
backendB
timeoutDuration 1s
cancelRunningFuturefalse
You can also override the default configuration, define shared configurations and overwrite them in Spring Boot’s application.yml
config file.
For example:
resilience4j.circuitbreaker
configs
default
slidingWindowSize100
permittedNumberOfCallsInHalfOpenState10
waitDurationInOpenState10000
failureRateThreshold60
eventConsumerBufferSize10
registerHealthIndicatortrue
someShared
slidingWindowSize50
permittedNumberOfCallsInHalfOpenState10
instances
backendA
baseConfig default
waitDurationInOpenState5000
backendB
baseConfig someShared
Using Customizer for specific instance names, you can also override the configuration of a particular CircuitBreaker, Bulkhead, Retry, RateLimiter or TimeLimiter instance. The following shows an example of how to override a configured CircuitBreaker backendA in the above YAML file:
public CircuitBreakerConfigCustomizer testCustomizer() {
return CircuitBreakerConfigCustomizer
.of("backendA", builder -> builder.slidingWindowSize(100));
}
Resilience4j has its own customizer types which can be used as shown above:
Resilienc4j Type | Instance Customizer class |
---|---|
Circuit breaker | CircuitBreakerConfigCustomizer |
Retry | RetryConfigCustomizer |
Rate limiter | RateLimiterConfigCustomizer |
Bulkhead | BulkheadConfigCustomizer |
ThreadPoolBulkhead | ThreadPoolBulkheadConfigCustomizer |
Time Limiter | TimeLimiterConfigCustomizer |
Annotations
The Spring Boot starter provides annotations and AOP Aspects which are auto-configured.
RateLimiter, Retry, CircuitBreaker and Bulkhead annotations support synchronous return types and asynchronous types like CompletableFuture and reactive types like Spring Reactor's Flux and Mono (if you imported an appropriate package like resilience4j-reactor
).
Bulkhead annotation has a type attribute to define which bulkhead implementation will be used. By default it is semaphore but you can switch to thread pool by setting the type attribute in the annotation:
name = BACKEND, type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> doSomethingAsync() throws InterruptedException {
Thread.sleep(500);
return CompletableFuture.completedFuture("Test");
}
(
Fallback methods
The fallback method mechanism works like a try/catch block. If a fallback method is configured, every exception is forwarded to a fallback method executor. The fallback method executor is searching for the best matching fallback method which can handle the exception. Similar to a catch block. The fallback is executed independently of the current state of the circuit breaker.
As an example:
name = BACKEND, fallbackMethod = "fallback")
(name = BACKEND)
(name = BACKEND, fallbackMethod = "fallback")
(name = BACKEND)
(name = BACKEND)
public Mono<String> method(String param1) {
return Mono.error(new NumberFormatException());
}
private Mono<String> fallback(String param1, CallNotPermittedException e) {
return Mono.just("Handled the exception when the CircuitBreaker is open");
}
private Mono<String> fallback(String param1, BulkheadFullException e) {
return Mono.just("Handled the exception when the Bulkhead is full");
}
private Mono<String> fallback(String param1, NumberFormatException e) {
return Mono.just("Handled the NumberFormatException");
}
private Mono<String> fallback(String param1, Exception e) {
return Mono.just("Handled any other exception");
}
(
It's important to remember that a fallback method should be placed in the same class and must have the same method signature with just ONE extra target 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, NumberFormatException 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.
Aspect order
The Resilience4j Aspects order is the following:
Retry ( CircuitBreaker ( RateLimiter ( TimeLimiter ( Bulkhead ( Function ) ) ) ) )
so Retry
is applied at the end (if needed).
If you need a different order, you must use the functional chaining style instead of the Spring annotations style or explicitly set aspect order using the following properties:
- resilience4j.retry.retryAspectOrder
- resilience4j.circuitbreaker.circuitBreakerAspectOrder
- resilience4j.ratelimiter.rateLimiterAspectOrder
- resilience4j.timelimiter.timeLimiterAspectOrder
- resilience4j.bulkhead.bulkheadAspectOrder
For example - to make Circuit Breaker starts after Retry finish its work you must set retryAspectOrder
property to greater value than circuitBreakerAspectOrder
value (the higher value = the higher priority).
resilience4j
circuitbreaker
circuitBreakerAspectOrder1
retry
retryAspectOrder2
Metrics endpoint
CircuitBreaker, Retry, RateLimiter, Bulkhead and TimeLimiter Metrics are automatically published on the Metrics endpoint. To retrieve the names of the available metrics, make a GET request to /actuator/metrics
. Please see Actuator Metrics documentation for more details.
{
"names": [
"resilience4j.circuitbreaker.calls",
"resilience4j.circuitbreaker.buffered.calls",
"resilience4j.circuitbreaker.state",
"resilience4j.circuitbreaker.failure.rate"
]
}
To retrieve a metric, make a GET request to /actuator/metrics/{metric.name}
.
For example: /actuator/metrics/resilience4j.circuitbreaker.calls
{
"name": "resilience4j.circuitbreaker.calls",
"measurements": [
{
"statistic": "VALUE",
"value": 3
}
],
"availableTags": [
{
"tag": "kind",
"values": [
"not_permitted",
"successful",
"failed"
]
},
{
"tag": "name",
"values": [
"backendB",
"backendA"
]
}
]
}
When you want to publish CircuitBreaker endpoints on the Prometheus endpoint, you have to add the dependency io.micrometer:micrometer-registry-prometheus
.
To retrieve metrics, make a GET request to /actuator/prometheus
. For more details please see Micrometer Getting Started
Health endpoint
Spring Boot Actuator health information can be used to check the status of your running application. It is often used by monitoring software to alert someone if a production system has serious issues.
By default the CircuitBreaker or RateLimiter health indicators are disabled, but you can enable them via the configuration. Health Indicators are disabled, because the application status is DOWN, when a CircuitBreaker is OPEN. This might not be what you want to achieve.
management.health.circuitbreakers.enabledtrue
management.health.ratelimiters.enabledtrue
resilience4j.circuitbreaker
configs
default
registerHealthIndicatortrue
resilience4j.ratelimiter
configs
instances
registerHealthIndicatortrue
A closed CircuitBreaker state is mapped to UP, an open state to DOWN and a half-open state to UNKNOWN.
For example:
{
"status": "UP",
"details": {
"circuitBreakers": {
"status": "UP",
"details": {
"backendB": {
"status": "UP",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 0,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 0,
"notPermittedCalls": 0,
"state": "CLOSED"
}
},
"backendA": {
"status": "UP",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 0,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 0,
"notPermittedCalls": 0,
"state": "CLOSED"
}
}
}
}
}
}
Events endpoint
The emitted CircuitBreaker, Retry, RateLimiter, Bulkhead and TimeLimiter events are stored in a separate circular event consumer buffers. The size of a event consumer buffer can be configured in the application.yml file (eventConsumerBufferSize).
The endpoint /actuator/circuitbreakers
lists the names of all CircuitBreaker instances. The endpoint is also available for Retry, RateLimiter, Bulkhead and TimeLimiter.
For example:
{
"circuitBreakers": [
"backendA",
"backendB"
]
}
The endpoint /actuator/circuitbreakerevents
lists by default the latest 100 emitted events of all CircuitBreaker instances. The endpoint is also available for Retry, RateLimiter, Bulkhead and TimeLimiter.
{
"circuitBreakerEvents": [
{
"circuitBreakerName": "backendA",
"type": "ERROR",
"creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]",
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
"durationInMs": 0
},
{
"circuitBreakerName": "backendA",
"type": "SUCCESS",
"creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]",
"durationInMs": 0
},
{
"circuitBreakerName": "backendB",
"type": "ERROR",
"creationTime": "2017-01-10T15:41:31.159+01:00[Europe/Berlin]",
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
"durationInMs": 0
},
{
"circuitBreakerName": "backendB",
"type": "SUCCESS",
"creationTime": "2017-01-10T15:41:33.526+01:00[Europe/Berlin]",
"durationInMs": 0
}
]
}
Updated about 2 months ago