首页 > 解决方案 > 如何重复调用不可靠的 API?Completable Future 会比编写在线程中运行的标准 try catch 块有用吗?

问题描述

我必须一次通过网络多次调用关键 API(这使得它不可靠),一天多次。如果 API 无法响应(超时)或返回错误(因为该服务器又在调用其他不可靠的第三方),我必须通知他们该错误,然后再次调用原始 API。

在这里,错误通知也可能失败,我将不得不重试通知错误,直到我成功。之后我可以再次调用原始 API。

我想使用 CompletableFuture 来构建它。对于这种代码,它是一个正确的库选择吗?或者我应该在 Runnable 中的无限循环中放置一个 try catch 循环并执行它?CompletableFuture 会过分吗?还有其他选择吗?

标签: multithreadingasynchronousarchitecturerunnablecompletable-future

解决方案


坦率地说,这个问题太宽泛了,因为答案真的取决于你已经在使用什么框架。问题是 - 今天有许多流行的框架提供开箱即用的重试逻辑实现。

例如:

但是,如果在考虑替代方案后您决定使用 手动重试CompletableFuture,您绝对可以这样做。

例如,这里有一些简单的重试实用程序:

  • 不限次数:
public static <T> CompletableFuture<T> retry(Throwable throwable, Function<Throwable, T> operation) {
    return CompletableFuture.supplyAsync(() -> operation.apply(throwable))
            .thenApply(CompletableFuture::completedFuture)
            .exceptionally(error -> retry(error, operation))
            .thenCompose(Function.identity());
}

注意:这里我假设,您可以根据Throwable. 因此,operation将错误作为输入并产生一些有用的结果作为输出。在您的情况下,错误 - 可能是critical API调用错误,或者notification error有用的结果 - 成功critical API的结果。

  • 固定次数(MAX_RETRIES在这种情况下):
public static <T> CompletableFuture<T> retry(Throwable throwable, Function<Throwable, T> operation, int retry) {
    if (retry == MAX_RETRIES) return failedFuture(throwable);

    return CompletableFuture.supplyAsync(() -> operation.apply(throwable))
            .thenApply(CompletableFuture::completedFuture)
            .exceptionally(error -> retry(error, operation, retry + 1))
            .thenCompose(Function.identity());
}

public static <T> CompletableFuture<T> failedFuture(Throwable throwable) {
    final CompletableFuture<T> failedFuture = new CompletableFuture<>();
    failedFuture.completeExceptionally(throwable);
    return failedFuture;
}

推荐阅读