Spring WebClient несколько повторов при обработке различных ошибок - PullRequest
1 голос
/ 30 мая 2020

Могу ли я добавить несколько retryWhen для выполнения повторных попыток обработки различных ответов об ошибках WebClient ?

Чего я хочу достичь:

Я использую WebClient для выполнения вызовов REST API. Есть несколько сценариев ошибок ios, когда мне нужно выполнить повторную попытку, но с разными задержками.

Например, 1. если происходит 401 Unauthorize, я могу повторить попытку сразу после обновления токена. 2. Если произошла ошибка 502/503 Server, мне нужно отложить повторные попытки через 5 секунд c. 3. Если происходит 429 Too Many Request, мне нужно отложить повторную попытку немного дольше, скажем, 20se c после.

Я хотел бы создать Retry spe c, как показано ниже:

    protected static final Predicate<Throwable> is401 =
                (throwable) -> throwable instanceof WebClientResponseException.Unauthorized;

        protected static final Predicate<Throwable> is5xx =
                (throwable) -> throwable instanceof WebClientResponseException.ServiceUnavailable;

        protected static final Predicate<Throwable> is429 =
                (throwable) -> throwable instanceof WebClientResponseException.TooManyRequests;

        Retry retry401 = Retry.fixedDelay(5, Duration.ofSeconds(1))
                    .filter(is401)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

        Retry retry5xx = Retry.fixedDelay(5, Duration.ofSeconds(10))
                    .filter(is5xx)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

        Retry retry429 = Retry.fixedDelay(5, Duration.ofSeconds(20))
                    .filter(is429)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

// trying to apply the to WebClient like below:
    WebClient.Builder()
        .get()
        .uri("endpointuri")
        .retrieve()
        .bodyToFlux(String.class)
        .retryWhen(retry401)
        .retryWhen(retry5xx)
        .retryWhen(retry429);

Похоже, что `.retryWhen (retry429) 'перезаписывает другие попытки.

1 Ответ

1 голос
/ 30 мая 2020

Похоже, что `.retryWhen (retry429) 'перезаписывает другие попытки.

Это неверно. retryWhen - составной оператор, который основан на существующем издателе - вы можете связывать его столько раз, сколько захотите. Единственный раз, когда вам нужно беспокоиться о том, что одна повторная попытка «переопределит» другую, - это когда ваши filter предикаты перекрываются.

Даже в этом случае похоже, что это «первая победа» (в цепочке), а не «последняя» wins ".

Вместо этого ваши проблемы могут быть связаны с этой строкой:

protected static final Predicate<Throwable> is5xx =
            (throwable) -> throwable instanceof WebClientResponseException.ServiceUnavailable;

Судя по вашему имени и вашему описанию, похоже, вы хотите, чтобы это перехватило любую ошибку 5xx, но это будет ловить только 503 (который специально назначен для "служба недоступна".)

Если вы пытаетесь сделать что-то другое, например, ошибку 502 или 500 - тогда ни один из предикатов (и, следовательно, повторных попыток) вы Будет найдено соответствие.

Вместо этого, чтобы проверить наличие ошибок 5xx, вы, вероятно, захотите:

protected static final Predicate<Throwable> is5xx =
        (throwable) -> throwable instanceof WebClientResponseException && ((WebClientResponseException)throwable).getStatusCode().is5xxServerError();
...