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
Yes, it is possible.
Mono
has two concepts for re-subscribing (and thus, re-triggering the request)
Each concept has multiple overloaded methods on Mono
for different use cases. Look for the retry*
and repeat*
methods.
For example, to retry a maximum number of times with no delay, use retry(int numRetries)
.
More complex use cases are supported via the retryWhen
and repeatWhen
methods, as shown in the following examples.
To retry if the mono completed with an exception a maximum of 5 times with 5 seconds between each attempt:
// From reactor-core >= v3.3.4.RELEASE
import reactor.util.retry.Retry;
this.webClient
.post()
.uri(SERVICE_URL)
.body(BodyInserters.fromValue(docRequest))
.retrieve()
.bodyToMono(Document.class)
.retryWhen(Retry.fixedDelay(5, Duration.ofSeconds(5)))
.delaySubscription(Duration.ofSeconds(10))
The retry builder supports other backoff strategies (e.g. exponential) and other options to fully customize retries.
Note the retryWhen(Retry)
method used above was added in reactor-core v3.3.4.RELEASE, and the retryWhen(Function)
method was deprecated.
Prior to reactor-core v3.3.4.RELEASE, you could use the retry function builder from reactor-extras project to create a Function
to pass to retryWhen(Function)
.
If you need to repeat on success, then use .repeatWhen
or .repeatWhenEmpty
instead of .retryWhen
above.
Use the repeat function builder from reactor-extras project to create the repeat Function
as follows:
// From reactor-extras
import reactor.retry.Repeat;
this.webClient
.post()
.uri(SERVICE_URL)
.body(BodyInserters.fromValue(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With