如何处理 CompletableFuture get() 方法的异常

How to handle exception of CompletableFuture get() method

我需要向第 3 方网址发送请求,所以我在 getStatus() 方法上使用了 @Async,其中 enum 的 returns CompletableFuture 并且如果 TimeoutException 被抛出我想考虑状态为 DOWN 或如何捕获每个调用的 InterruptedExceptionExecutionException

try {
    firstAppStatus = service1.getStatus().get(20, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    firstAppStatus = ComponentStatusEnum.DOWN;
}
try {
    secondAppStatus = service2.getStatus().get(20, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    secondAppStatus = ComponentStatusEnum.DOWN;
}
try {
    thirdAppStatus = service3.getStatus().get(20, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    thirdAppStatus = ComponentStatusEnum.DOWN;
}

我知道此代码将按顺序执行,所以 运行 它们如何与此行为异步而不对客户端请求超时进行更改

使用 Java 9 你可以使用 completeOnTimeout:

CompletableFuture<ComponentStatusEnum> firstAppStatus = service1.getStatus().completeOnTimeout(ComponentStatusEnum.DOWN, 20, TimeUnit.SECONDS);

更多信息here

如果我没理解错的话,你想要这样的东西:

// allow all three requests to run concurrently
CompletableFuture<ComponentStatusEnum> status1 = service1.getStatus();
CompletableFuture<ComponentStatusEnum> status2 = service2.getStatus();
CompletableFuture<ComponentStatusEnum> status3 = service3.getStatus();

// wait for either, the completion of all three or the timeout, whatever comes first
try {
    CompletableFuture.allOf(status1, status2, status3).get(20, TimeUnit.SECONDS);
} catch(TimeoutException|InterruptedException|ExecutionException ex) {
    // no action, as all cases are handled below
}

// get results with fall-backs on timeout
firstAppStatus  = status1.getNow(ComponentStatusEnum.DOWN);
secondAppStatus = status2.getNow(ComponentStatusEnum.DOWN);
thirdAppStatus  = status3.getNow(ComponentStatusEnum.DOWN);

首先,如果要让所有请求运行并行,不要立即查询结果。然后,使用allOf,您可以等待所有操作的完成与单个超时。

getNow 是在可用时立即获取结果的正确操作,如果操作尚未完成,则为指定的回退值。原则上,操作可能会在获取 TimeoutException 和调用 getNow 之间的短暂 window 时间内完成,但这不会对您的应用程序逻辑造成任何问题。

关于异常处理,getNow 的行为类似于 join() 在基础操作失败时抛出未经检查的 CompletionException 而不是已检查的 ExecutionException。如果你没有捕捉到它,它会传播给调用者,如果你对这种情况没有特殊处理,这是最好的选择。如果超时等待被打断,它的行为就像你有一个更小的超时一样;操作可能已经完成或在 getNow.

获得回退值