-
-
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!
i'm using
quarkus-resteasy-mutiny
with Quarkus version 2.5.0.Final (Mutiny 1.1.2)