-
-
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); | |
} | |
} |
Yup, i see: Suppressed: java.lang.IllegalStateException: Retries exhausted: 5/5
I also tried to "catch" the specific IllegalStateException in the second onFailure, but the following recoverWithItem does not take place and the exception in thrown instead.
Which version of mutiny are you using? I think we added the last exception to the suppressed list.
i'm using quarkus-resteasy-mutiny
with Quarkus version 2.5.0.Final (Mutiny 1.1.2)
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!
Don't you have the exception in the suppressed exception list?