spring webclient: retry with backoff on specific error spring webclient: retry with backoff on specific error spring spring

spring webclient: retry with backoff on specific error


With reactor-extra you could do it like:

.retryWhen(Retry.onlyIf(this::is5xxServerError)        .fixedBackoff(Duration.ofSeconds(10))        .retryMax(3))private boolean is5xxServerError(RetryContext<Object> retryContext) {    return retryContext.exception() instanceof WebClientResponseException &&            ((WebClientResponseException) retryContext.exception()).getStatusCode().is5xxServerError();}

Update:With new API the same solution will be:

    .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(10))            .filter(this::is5xxServerError));//...private boolean is5xxServerError(Throwable throwable) {    return throwable instanceof WebClientResponseException &&            ((WebClientResponseException) throwable).getStatusCode().is5xxServerError();}


You can do this taking the following approach:

  • Use the exchange() method to obtain the response without an exception, and then throw a specific (custom) exception on a 5xx response (this differs from retrieve() which will always throw WebClientResponseException with either a 4xx or 5xx status);
  • Intercept this specific exception in your retry logic;
  • Use reactor-extra - it contains a nice way to use retryWhen() for more complex & specific retries. You can then specify a random backoff retry that starts after 10 seconds, goes up to an arbitrary time and tries a maximum of 3 times. (Or you can use the other available methods to pick a different strategy of course.)

For example:

//...webclient.exchange().flatMap(clientResponse -> {    if (clientResponse.statusCode().is5xxServerError()) {        return Mono.error(new ServerErrorException());    } else {        //Any further processing    }}).retryWhen(    Retry.anyOf(ServerErrorException.class)       .randomBackoff(Duration.ofSeconds(10), Duration.ofHours(1))       .maxRetries(3)    ));


the retryWhen with Retry.anyOf and Retry.onlyIf are deprecated I assume. I found this approach useful, and it allows us to process and throw a User defined exception.

for example :

retryWhen(Retry.backoff(3, Duration.of(2, ChronoUnit.SECONDS))                        .filter(error -> error instanceof UserDefinedException/AnyOtherException)                        .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) ->                                new UserDefinedException(retrySignal.failure().getMessage())))