Zab*_*uza 12 java http request retry-logic java-http-client
使用HttpClientJava 11(JDK,而不是 Apache),如何重试请求?
假设我想重试一个请求最多10 次,如果它没有返回状态代码或200抛出异常。
目前,我正在循环中重新安排返回的未来,我想知道是否有更好或更优雅的方式。
CompletableFuture<HttpResponse<Foo>> task = client.sendAsync(request, bodyHandler);
for (int i = 0; i < 10; i++) {
task = task.thenComposeAsync(response -> response.statusCode() == 200 ?
CompletableFuture.completedFuture(response) :
client.sendAsync(request, bodyHandler));
}
// Do something with 'task' ...
Run Code Online (Sandbox Code Playgroud)
如果我们也为特殊情况添加重试,我最终会得到
CompletableFuture<HttpResponse<Foo>> task = client.sendAsync(request, bodyHandler);
for (int i = 0; i < 10; i++) {
task = task.thenComposeAsync(response ->
response.statusCode() == 200 ?
CompletableFuture.completedFuture(response) :
client.sendAsync(request, bodyHandler))
.exceptionallyComposeAsync(e ->
client.sendAsync(request, bodyHandler));
}
// Do something with 'task' ...
Run Code Online (Sandbox Code Playgroud)
不幸的是,似乎没有任何composeAsync触发器可以同时触发常规完成和异常。有handleAsync但没有compose,lambda 需要返回U但不CompletionStage<U>存在。
为了进行质量检查,我也对展示如何使用其他框架实现这一目标的答案感兴趣,但我不会接受它们。
例如,我见过一个名为Failsafe的库,它可能为此提供一个优雅的解决方案(请参阅jodah.net/failsafe)。
作为参考,以下是一些相关的 JavaDoc 链接:
我建议按照这些思路做一些事情(假设没有安全经理):
public static int MAX_RESEND = 10;
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpResponse.BodyHandler<String> handler = HttpResponse.BodyHandlers.ofString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://example.com/")).build();
var response = client.sendAsync(request, handler)
.thenComposeAsync(r -> tryResend(client, request, handler, 1, r));
// do something with response...
}
public static <T> CompletableFuture<HttpResponse<T>>
tryResend(HttpClient client, HttpRequest request, BodyHandler<T> handler,
int count, HttpResponse<T> resp) {
if (resp.statusCode() == 200 || count >= MAX_RESEND) {
return CompletableFuture.completedFuture(resp);
} else {
return client.sendAsync(request, handler)
.thenComposeAsync(r -> tryResend(client, request, handler, count+1, r));
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想同时处理常规和特殊情况,你可以这样做:
public static int MAX_RESEND = 5;
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
BodyHandler<String> handler = BodyHandlers.ofString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://example.com/")).build();
CompletableFuture<HttpResponse<String>> response =
client.sendAsync(request, handler)
.handleAsync((r, t) -> tryResend(client, request, handler, 1, r, t))
.thenCompose(Function.identity());
// do something with response ...
}
public static boolean shouldRetry(HttpResponse<?> r, Throwable t, int count) {
if (r != null && r.statusCode() == 200 || count >= MAX_RESEND) return false;
if (t instanceof ... ) return false;
return true;
}
public static <T> CompletableFuture<HttpResponse<T>>
tryResend(HttpClient client, HttpRequest request,
BodyHandler<T> handler, int count,
HttpResponse<T> resp, Throwable t) {
if (shouldRetry(resp, t, count)) {
return client.sendAsync(request, handler)
.handleAsync((r, x) -> tryResend(client, request, handler, count + 1, r, x))
.thenCompose(Function.identity());
} else if (t != null) {
return CompletableFuture.failedFuture(t);
} else {
return CompletableFuture.completedFuture(resp);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15458 次 |
| 最近记录: |