CodeDevStack

Resilience4j in Spring Boot, WebClient and no annotations

February 12, 2020

Is this even a circuit breaker?

Today I was working on adding Resilience4j to our Spring Boot app and noticed that most of the examples online are not very clear about how to use it with Reactor if you are not using annotations. So here we’ll go through a simple, but full example of how to circuit break a WebClient Mono stream.

This is our initial WebClient call we want to circuit break.

Mono<String> response = WebClient.create(url)
                                .get()
                                .bodyToMono(String.class);//myResponse

In order to do this we need to:

  1. Add dependencies for Resilience4j spring boot and Resilience4j reactor.
  2. Setup a basic configuration using Spring YAML files.
  3. Inject CircuitBreakerRegistry bean.
  4. Create an instance of circuit breaker from the registry.
  5. Add the circuit breaker to the WebClient stream.

1. Add dependencies for Resilience4j spring boot and Resilience4j reactor

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-reactor</artifactId>
    <version>1.3.1</version>
</dependency>

2. Setup a basic configuration using Spring YAML files.

You can use the default config, set a very basic configuration or set up some pretty complex rules for different circuit breakers. The following is an example with only a few properties set.

resilience4j.circuitbreaker:
    configs:
        default:
            slidingWindowSize: 100
            permittedNumberOfCallsInHalfOpenState: 10
            waitDurationInOpenState: 10000
            failureRateThreshold: 60

3. Inject CircuitBreakerRegistry bean.

Autowire the dependency into your desired bean.

@Autowired
private CircuitBreakerRegistry circuitBreakerRegistry;

4. Create an instance of circuit breaker from the registry.

You can do this inside the method where you are also using WebClient.

CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("MY_CIRCUIT_BREAKER");

5. Add the circuit breaker to the WebClient stream.

CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("MY_CIRCUIT_BREAKER");

Mono<String> response = WebClient.create(url)
                                .get()
                                .bodyToMono(String.class);//myResponse
                                .compose(CircuitBreakerOperator.of(circuitBreaker))

We are using the compose operator. This operator is applied at the time of subscription, this way the circuit breaker can decide if it should allow or disallow passage at subscription time. In our example, every time we want to make the WebClient call, the circuit breaker decides what to do.

So where do we use our fallback method? The circuit breaker will emit an Error downstream, so all we need to do is handle it and resume.

CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("MY_CIRCUIT_BREAKER");

Mono<String> response = WebClient.create(url)
                                .get()
                                .bodyToMono(String.class);//myResponse
                                .compose(CircuitBreakerOperator.of(circuitBreaker))
                                .onErrorResume(error -> Mono.just("fallback mono!"));

This way, when the circuit breaker is open( not making the WebClient call), it will emit an Error and we’ll just handle it by returning a new publisher( Mono.just()) downstream.