-
-
Save cescoffier/e9abce907a1c3d05d70bea3dae6dc3d5 to your computer and use it in GitHub Desktop.
| //usr/bin/env jbang "$0" "$@" ; exit $? | |
| //DEPS io.smallrye.reactive:smallrye-mutiny-vertx-web-client:1.1.0 | |
| //DEPS io.smallrye.reactive:mutiny:0.7.0 | |
| //DEPS org.slf4j:slf4j-nop:1.7.30 | |
| package io.vertx.mutiny.retry; | |
| import io.smallrye.mutiny.Uni; | |
| import io.vertx.mutiny.core.Vertx; | |
| import io.vertx.mutiny.ext.web.client.WebClient; | |
| import java.time.Duration; | |
| import java.util.Random; | |
| /** | |
| * Various examples of retries. | |
| * CTRL+C to exist. | |
| */ | |
| public class Retry { | |
| public static void main(String[] args) { | |
| Vertx vertx = Vertx.vertx(); | |
| WebClient client = WebClient.create(vertx); | |
| // Just start a picky service failing 50% of the times. | |
| startPickyService(vertx); | |
| System.out.println("Hit CTRL+C to exit the program"); | |
| // Retrying forever | |
| invokePickyService(client) | |
| .onFailure().retry().indefinitely() | |
| .subscribe().with(item -> System.out.println("[Retrying forever]: " + item)); | |
| // Retrying at most twice | |
| invokePickyService(client) | |
| .onFailure().retry().atMost(2) | |
| .subscribe().with( | |
| item -> System.out.println("[Retrying atMost(2)]: " + item), | |
| failure -> System.out.println("[Retrying atMost(2) failed]: " + failure.getMessage()) | |
| ); | |
| // Retrying with backoff | |
| invokePickyService(client) | |
| .onFailure().retry().withBackOff(Duration.ofSeconds(1)).withJitter(0.2).atMost(10) | |
| .subscribe().with( | |
| item -> System.out.println("[Retrying backoff]: " + item), | |
| failure -> System.out.println("[Retrying backoff failed]: " + failure.getMessage()) | |
| ); | |
| // Retrying with backoff and deadline | |
| invokePickyService(client) | |
| .onFailure().retry().withBackOff(Duration.ofSeconds(1)).withJitter(0.2) | |
| .expireIn(5000) | |
| .subscribe().with( | |
| item -> System.out.println("[Retrying backoff with deadline]: " + item), | |
| failure -> System.out.println("[Retrying backoff with deadline]: " + failure.getMessage()) | |
| ); | |
| } | |
| private static Uni<String> invokePickyService(WebClient client) { | |
| return client.getAbs("http://localhost:8080") | |
| .send() | |
| .onItem().transform(resp -> { | |
| if (resp.statusCode() == 200) { | |
| return resp.bodyAsString(); | |
| } else { | |
| throw new IllegalStateException(resp.bodyAsString()); | |
| } | |
| }); | |
| } | |
| private static void startPickyService(Vertx vertx) { | |
| Random random = new Random(); | |
| vertx.createHttpServer() | |
| .requestHandler(req -> { | |
| if (random.nextBoolean()) { | |
| req.response().endAndForget("Hello!"); | |
| } else { | |
| req.response().setStatusCode(500).endAndForget("Not in a mood"); | |
| } | |
| }) | |
| .listenAndAwait(8080); | |
| } | |
| } |
In addition, i also tried to retrieve the IllegalStateException suppressed showing the number of retries attempted:
.onFailure((failure) -> Arrays.stream(failure.getSuppressed()).anyMatch(f -> f instanceof IllegalStateException))It exits from the retry block after the first iteration (http client stub is called only once in my test)
Hello @cescoffier,
Is it possible to retry a request and for each request, wait a certain ammount of seconds? The following code waits 30 seconds but it is considering all of the retries. What i would like to do is to wait 30 seconds for the response everytime it retries.
WebClient.create(vertx)
.get(endpoint)
.send()
.onItem()
.transformToMulti(response -> {
........................................................
return Uni.createFrom().item(response.bodyAsJsonObject().getJsonArray("content")).toMulti();
})
.onFailure()
.retry()
.withBackOff(Duration.ofSeconds(5), Duration.ofSeconds(10))
.withJitter(0.7)
.atMost(3)
.onFailure().invoke(error -> log.error("Didn't work.")
.toUni()
.await()
.atMost(Duration.ofSeconds(30));
Thank you!
Looks like dependencies should be updated:
$ jbang https://gist.github.com/cescoffier/e9abce907a1c3d05d70bea3dae6dc3d5
[jbang] Resolving dependencies...
[jbang] io.smallrye.reactive:smallrye-mutiny-vertx-web-client:1.1.0
[jbang] io.smallrye.reactive:mutiny:0.7.0
[jbang] org.slf4j:slf4j-nop:1.7.30
[jbang] [ERROR] Could not resolve dependencies: Failed to collect dependencies at io.smallrye.reactive:smallrye-mutiny-vertx-web-client:jar:1.1.0
[jbang] Run with --verbose for more details
I've discovered that running this in a thread/context that includes a Mutiny Hibernate Reactive Session (for example, when retrying a database call), causes an error when using .withBackOff(...)
java.lang.IllegalStateException: HR000068: This method should
exclusively be invoked from a Vert.x EventLoop thread; currently running on thread 'executor-thread-1'
I think this behaviour is known since I assume the retry runs on a worker thread? Without .withBackOff(...) everything works, but I wonder if there is a way around this.
i'm using
quarkus-resteasy-mutinywith Quarkus version 2.5.0.Final (Mutiny 1.1.2)