Getting Started
Getting started with resilience4j-micronaut
Setup
Add the Micronaut Starter of Resilience4j to your compile dependency.
include the maven bom for micronaut dependencies io.micronaut:micronaut-bom:2.0.0.M3
.
repositories {
mavenCentral()
jCenter()
}
dependencyManagement {
imports {
mavenBom 'io.micronaut:micronaut-bom:2.0.0.M3'
}
}
dependencies {
annotationProcessor "io.micronaut:micronaut-inject-java"
annotationProcessor "io.micronaut:micronaut-validation"
compile "io.github.resilience4j:resilience4j-micronaut:${resilience4jVersion}"
}
Demo
Setup and usage in Micronaut is demonstrated into a demo.
Configuration
You can configure your CircuitBreaker, Retry, RateLimiter, Bulkhead, Thread pool bulkhead and TimeLimiter instances in Micronaut’s application.yml
config file.
For example
resilience4j:
circuitbreaker:
enabled: true
instances:
backendA:
baseConfig: default
backendB:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 10
permittedNumberOfCallsInHalfOpenState: 3
waitDurationInOpenState: PT5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
recordFailurePredicate: resilience4j.micronaut.demo.exception.RecordFailurePredicate
configs:
default:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: PT5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
recordExceptions:
- io.micronaut.http.exceptions.HttpStatusException
- java.util.concurrent.TimeoutException
- java.io.IOException
ignoreExceptions:
- resilience4j.micronaut.demo.exception.BusinessException
shared:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 30
waitDurationInOpenState: PT1s
failureRateThreshold: 50
eventConsumerBufferSize: 10
ignoreExceptions:
- resilience4j.micronaut.demo.exception.BusinessException
retry:
enabled: true
configs:
default:
maxAttempts: 3
waitDuration: 100
retryExceptions:
- io.micronaut.http.exceptions.HttpStatusException
- java.util.concurrent.TimeoutException
- java.io.IOException
ignoreExceptions:
- resilience4j.micronaut.demo.exception.BusinessException
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
bulkhead:
enabled: true
configs:
default:
maxConcurrentCalls: 100
instances:
backendA:
maxConcurrentCalls: 10
backendB:
maxWaitDuration: PT0.01S
maxConcurrentCalls: 20
thread-pool-bulkhead:
enabled: true
configs:
default:
maxThreadPoolSize: 4
coreThreadPoolSize: 2
queueCapacity: 2
instances:
backendA:
baseConfig: default
backendB:
maxThreadPoolSize: 1
coreThreadPoolSize: 1
queueCapacity: 1
ratelimiter:
enabled: true
configs:
default:
registerHealthIndicator: false
limitForPeriod: 10
limitRefreshPeriod: 1s
timeoutDuration: 0
eventConsumerBufferSize: 100
instances:
backendA:
baseConfig: default
backendB:
limitForPeriod: 6
limitRefreshPeriod: PT0.5S
timeoutDuration: 3s
timelimiter:
enabled: true
configs:
default:
cancelRunningFuture: false
timeoutDuration: PT2s
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
You can also override the default configuration, define shared configurations and overwrite them in Micronaut’s application.yml
config file.
For example:
resilience4j:
circuitbreaker:
enabled: true
configs:
default:
eventConsumerBufferSize: 10
failureRateThreshold: 60
permittedNumberOfCallsInHalfOpenState: 10
registerHealthIndicator: true
slidingWindowSize: 100
waitDurationInOpenState: 10000
someShared:
permittedNumberOfCallsInHalfOpenState: 10
slidingWindowSize: 50
instances:
backendA:
baseConfig: default
waitDurationInOpenState: 5000
backendB:
baseConfig: someShared
You can also override the configuration of a specific CircuitBreaker, Bulkhead, Retry, RateLimiter or TimeLimiter instances by using Customizer for specific instance names. The following shows an example of how to override a configured CircuitBreaker backendA in the above in the YAML file:
@Bean
@CircuitBreakerQualifier
public CircuitBreakerConfigCustomizer testCustomizer() {
return CircuitBreakerConfigCustomizer
.of("backendA", builder -> builder.slidingWindowSize(100));
}
Resilience4j has its own customizer types which can be used as shown above. The beans have to be marked with the correct Qualifier:
Resilienc4j Type | Instance Customizer class | Qualifier |
---|---|---|
Circuit breaker | CircuitBreakerConfigCustomizer | @CircuitBreakerQualifier |
Retry | RetryConfigCustomizer | @RetryQualifier |
Rate limiter | RateLimiterConfigCustomizer | @RateLimiterQualifier |
Bulkhead | BulkheadConfigCustomizer | @BulkheadQualifier |
ThreadPoolBulkhead | ThreadPoolBulkheadConfigCustomizer | @ThreadPoolBulkheadQualifier |
Time Limiter | TimeLimiterConfigCustomizer | @TimeLimiterQualifier |
Configuration through Interceptor
beans can be intercepted before they are injected. so additional customization can be issued through intercepting the Resilience4j properties.
package io.micronaut.ignite.docs.config;
@Singleton
public class BulkheadConfiguration implements BeanCreatedEventListener<BulkheadProperties> {
@Override
public IgniteConfiguration onCreated(BeanCreatedEvent<BulkheadConfigurationProperties> event) {
CircuitBreakerProperties configuration = event.getBean();
return configuration;
}
}
Resilience4j Type |
---|
BulkheadConfigurationProperties |
CircuitBreakerConfigurationProperties |
RateLimiterProperties |
RetryProperties |
TimeLimiterProperties |
ThreadPoolBulkheadProperties |
Annotations
The Micronaut 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 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:
@Bulkhead(name = BACKEND_A, type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> futureFailure() {
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new IOException("BAM!"));
return future;
}
An example of all resilience4j supported spring aspects
@Override
@Bulkhead(name = BACKEND_A, type = Bulkhead.Type.THREADPOOL)
@TimeLimiter(name = BACKEND_A)
@CircuitBreaker(name = BACKEND_A, fallbackMethod = "futureFallback")
public CompletableFuture<String> futureTimeout() {
Try.run(() -> Thread.sleep(5000));
return CompletableFuture.completedFuture("Hello World from backend A");
}
@Executable
public String fallback() {
return "Recovered HttpServerErrorException";
}
@Executable
public CompletableFuture<String> futureFallback() {
return CompletableFuture.completedFuture("Recovered specific TimeoutException");
}
It's important to remember that a fallback method should be placed in the same class and must be marked with @Executable.
The fallback method has to have the same matching argument signature and the same matching return type.
Aspect order
The Resilience4j Aspects order is following: Retry ( CircuitBreaker ( RateLimiter ( TimeLimiter ( Bulkhead ( Function ) ) ) ) )
There is currently no way to change the order of the executing aspects.
Updated over 3 years ago