问题
What i want to do is a conditional repeat on a Mono in Webflux with webclient.The Situation is the following:
We have some business rest service service that returns a generated document. the generation of this document is triggered from another service that gets called before this one. But, back to business: the document generation service needs from 10-30 seconds. What we want to do is: check after 10 seconds if document (Mono) is generated. If so, all is fine. If not, repeat (or retry) after another 5 seconds and check if document is generated. And so on until (worst case) a timeout after 30 seconds. Is this possible? Some (pseudo) code:
return this.webClient.post().uri(SERVICE_URL)).
body(BodyInserters.fromObject(docRequest)).retrieve().
bodyToMono(Document.class).
delaySubscription(Duration.ofSeconds(10)).
repeat5TimesWithDynamicTimeDelayUntil(!document.isEmpty()).
subscribe();
Greetz Bernardo
回答1:
Yes, it is possible.
Mono
has two concepts for re-subscribing (and thus, re-triggering the request)
- retry = re-subscribe if the upstream completed with an exception
- repeat = re-subscribe if the upstream completed successfully
Each concept has multiple overloaded methods on Mono
for different use cases. Look for the retry*
and repeat*
methods.
For example, a common use case is retrying with an exponential backoff strategy via retryBackoff
.
More complex use cases are supported via retryWhen
and repeatWhen
. The reactor-extras project includes some builders to help you build the Functions to pass to those methods.
Here is an example that retries if the mono completed with an exception a maximum of 5 times with 5 seconds between each attempt
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))
There are other Backoff strategies (e.g. exponential), and other options available to fully customize retries (e.g. using a timeout instead of max number of retries).
If you need to repeat on success, then use .repeatWhen(Repeat...)
or .repeatWhenEmpty(Repeat...)
instead of .retryWhen(Retry...)
above. For example:
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))
You can also chain a .retry*
with a .repeat*
if you want to re-subscribe on both success or failure.
来源:https://stackoverflow.com/questions/55923326/conditional-repeat-or-retry-on-mono-with-webclient-from-spring-webflux