Условное повторение или повтор на Mono с веб-клиентом из Spring WebFlux - PullRequest
0 голосов
/ 30 апреля 2019

То, что я хочу сделать, это условное повторение Mono в Webflux с webclient. Ситуация следующая:

У нас есть служба бизнес-отдыха, которая возвращает сгенерированный документ. генерация этого документа запускается из другой службы, которая вызывается до этой. Но вернемся к делу: сервису генерации документов требуется от 10-30 секунд. Что мы хотим сделать: проверить через 10 секунд, генерируется ли документ (Mono). Если так, все в порядке. Если нет, повторите (или повторите) через 5 секунд и проверьте, создан ли документ. И так до истечения (в худшем случае) тайм-аута через 30 секунд. Это возможно? Некоторый (псевдо) код:

return this.webClient.post().uri(SERVICE_URL)).        
body(BodyInserters.fromObject(docRequest)).retrieve().
bodyToMono(Document.class).
delaySubscription(Duration.ofSeconds(10)).
repeat5TimesWithDynamicTimeDelayUntil(!document.isEmpty()).
subscribe();

Greetz Бернардо

1 Ответ

0 голосов
/ 01 мая 2019

Да, это возможно.

Mono имеет две концепции для повторной подписки (и, следовательно, повторного запуска запроса)

  • retry = повторная подписка, если восходящий поток завершен с исключением
  • повтор = повторная подписка, если восходящий поток успешно завершен

Каждая концепция имеет несколько перегруженных методов в Mono для разных вариантов использования. Ищите методы retry* и repeat*. Например, обычный вариант использования - это повторная попытка с использованием стратегии экспоненциального отката с помощью retryBackoff.

.

Более сложные варианты использования поддерживаются через retryWhen и repeatWhen. Проект реактор-дополнительные включает в себя несколько сборщиков, которые помогут вам построить функции для перехода к этим методам.

Вот пример, который повторяется, если моно завершено с исключением максимум 5 раз с 5 секундами между каждой попыткой

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromObject(docRequest))
        .retrieve()
        .bodyToMono(Document.class)
        .retryWhen(Retry.any()
                .fixedBackoff(Duration.ofSeconds(5))
                .retryMax(5))
        .delaySubscription(Duration.ofSeconds(10))

Существуют другие стратегии возврата (например, экспоненциальный) и другие параметры, доступные для полной настройки повторных попыток (например, использование тайм-аута вместо максимального количества повторных попыток).

Если вам нужно повторить в случае успеха, используйте .repeatWhen(Repeat...) или .repeatWhenEmpty(Repeat...) вместо .retryWhen(Retry...) выше. Например:

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromObject(docRequest))
        .retrieve()
        .bodyToMono(Document.class)
        .filter(document -> !document.isEmpty())
        .repeatWhenEmpty(Repeat.onlyIf(repeatContext -> true)
                .exponentialBackoff(Duration.ofSeconds(5), Duration.ofSeconds(10))
                .timeout(Duration.ofSeconds(30)))
        .delaySubscription(Duration.ofSeconds(10))

Вы также можете связать .retry* с .repeat*, если хотите повторно подписаться как на успех, так и на неудачу.

...