spring webclient: retry with backoff on specific error

前端 未结 4 1318
后悔当初
后悔当初 2021-01-12 16:07

i\'d like to retry the request 3 times after waiting 10sec when response is 5xx. but i don\'t see a method that I can use. On object

WebClient.builder()
             


        
相关标签:
4条回答
  • 2021-01-12 16:50

    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();
    }
    
    0 讨论(0)
  • 2021-01-12 17:08
    // ...
    .retryWhen(
        backoff(maxAttempts, minBackoff)
            .filter(throwable -> ((WebClientResponseException) throwable).getStatusCode().is5xxServerError()))
    // ...
    
    0 讨论(0)
  • 2021-01-12 17:09

    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())))
    
    0 讨论(0)
  • 2021-01-12 17:11

    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)
        )
    );
    
    0 讨论(0)
提交回复
热议问题