Spring webclient: повторите попытку с определенной ошибкой - PullRequest
4 голосов
/ 23 октября 2019

Я хотел бы повторить запрос 3 раза после ожидания 10 секунд, когда ответ 5xx. но я не вижу метод, который я могу использовать. На объекте

WebClient.builder()
                .baseUrl("...").build().post()
                .retrieve().bodyToMono(...)

я вижу методы:

повторная попытка при условии с количеством повторов, но без задержки

.retry(3, {it is WebClientResponseException && it.statusCode.is5xxServerError} )

повторная попытка с откатом и количеством раз, но без условия

.retryBackoff 

есть также retryWhen, но я не уверен, как его использовать

Ответы [ 2 ]

1 голос
/ 23 октября 2019

С реактором-экстра вы можете сделать это следующим образом:

.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();
}
1 голос
/ 23 октября 2019

Вы можете сделать это, используя следующий подход:

  • Используйте метод exchange(), чтобы получить ответ без исключения, а затем вызвать конкретное (пользовательское) исключение для ответа 5xx (этоотличается от retrieve(), который всегда будет выдавать WebClientResponseException со статусом 4xx или 5xx);
  • Перехватить это конкретное исключение в логике повторных попыток;
  • Использовать reactor-extra - содержит удобный способ использования retryWhen() для более сложных и специфических попыток. Затем вы можете указать случайную повторную попытку отката, которая начинается через 10 секунд, увеличивается до произвольного времени и повторяется не более 3 раз. (Или вы можете использовать другие доступные методы для выбора другой стратегии, конечно.)

Например:

//...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)
    )
);
...