Home > front end >  Implement Retry mechanism using Mono.retry() within Spring WebFlux Reactive code
Implement Retry mechanism using Mono.retry() within Spring WebFlux Reactive code

Time:09-28

Am using Java 8 and Spring WebFlux to call an external REST based server which also has a backup server.

Currently, if there's a failure when calling the server, it hits the backup server with no retry mechanism:

public class ServiceImpl {

    @Autowired
    MyRestClient myRestClient;

    @Autowired
    MyRestClient myRestClientBackup;

    public Mono<ResponseOutput> getResponseOutput(ResponseInput responseInput) {
        return Mono.just(responseInput)
            .flatMap(input -> {
                Mono<ResponseOutput> mono = myRestClient.post(input)
                    .doOnSuccess(responseOutput -> {
                        log.info("Successfully got responseOutput={}", responseOutput);
                    });
                return mono;
            })
            .onErrorResume(e -> {
                log.warn("Call to server failed, falling back to backup server...");
                Mono<ResponseOutput> mono = myRestClientBackup.post(responseInput)
                        .doOnSuccess(responseOutput ->
                                log.info("Successfully got backup responseOutput={}", responseOutput));
                return mono;
            });

    }
}

Am trying to implement a retry mechanism where upon setting a numRetries property in application.yml set to a specific number, this should happen:

e.g. if the numRetries = 2

Use MyRestClient to hit the original server twice (since numRetries = 2) and if that fails to hit the backup server.


This has the numRetries configuration property set to a static value:

application.yml:

client:
   numRetries: 2;

Class that loads config properties from application.yml file:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public ClientConfig {

    @Value("${client.numRetries:0}")
    private int numRetries;

    // Getters and setters omitted for brevity
}

ClientConfig is used by MyRestClient:

public class MyRestClient {

    @Autowired 
    ClientConfig   config;

    // Getters and setters omitted for brevity
}

Upon obtaining the value for the numRetries from MyRestClient how can I change the original implementation inside ServiceImpl.getResponseOutput() to use numRetries to hit the original server before calling the backup server? As you can see that this is all originally done using Java 8 lambda and streams...

Found this annotation @Retryable(value = RestClientException.class) but don't know how to specify the else if numRetries is used to call the backup server (pseudocode)?

Is there a lambda function to denote the numRetries to use within the:

return Mono.just(responseInput)
            .flatMap(input -> {

How to do use the Mono.retry() operator?

Also, the version of reactor in this code seems to have deprecated the Mono.retry().retryBackOff() method?

How could I use the value referencing numRetries (which would be an int) to dictate to keep retrying (upon failure) and then when numRetries is exceeded up .onErrorResume() to call the other backup server?

CodePudding user response:

Use retry(int) operator from Mono as below:

Mono.just(responseInput)
    .flatMap(input -> myRestClient.post(input)
        .retry(getNumRetries()) // this is the important part
        .doOnSuccess(responseOutput -> log.info("Successfully got responseOutput={}", responseOutput)))
    .onErrorResume(e -> {
        log.warn("Call to server failed, falling back to backup server...");
        return myRestClientBackup.post(responseInput)
            .doOnSuccess(responseOutput -> log.info("Successfully got backup responseOutput={}", responseOutput));
    });
  • Related