英文:
How to handle exception of CompletableFuture get() method
问题
我需要向第三方网址发送请求,因此我在getStatus()
方法上使用了@Async
,该方法返回enum
的CompletableFuture
,如果抛出TimeoutException
,我希望将状态视为DOWN,或者如何捕获每次调用的InterruptedException
和ExecutionException
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;
}
我知道这段代码将按顺序执行,所以如何在不更改客户端请求超时的情况下以异步方式运行它们
英文:
I need to to send requests to 3rd party urls so i used @Async
on getStatus()
method which returns CompletableFuture
of enum
and if TimeoutException
is thrown i'd like to consider status as DOWN or how to catch InterruptedException
and ExecutionException
of each call
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;
}
I know this code will executed sequentially so how run them asynchronous with this behavior without making changes on client request timeout
答案1
得分: 3
如果我理解你的意思正确,你想要类似以下的代码:
// 允许所有三个请求并发运行
CompletableFuture<ComponentStatusEnum> status1 = service1.getStatus();
CompletableFuture<ComponentStatusEnum> status2 = service2.getStatus();
CompletableFuture<ComponentStatusEnum> status3 = service3.getStatus();
// 等待三个请求全部完成或超时,以先发生的为准
try {
CompletableFuture.allOf(status1, status2, status3).get(20, TimeUnit.SECONDS);
} catch (TimeoutException|InterruptedException|ExecutionException ex) {
// 无操作,因为所有情况都在下面处理
}
// 使用超时时的回退值获取结果
firstAppStatus = status1.getNow(ComponentStatusEnum.DOWN);
secondAppStatus = status2.getNow(ComponentStatusEnum.DOWN);
thirdAppStatus = status3.getNow(ComponentStatusEnum.DOWN);
首先,如果你想允许所有请求并行运行,不要立即查询结果。然后,使用allOf
,你可以等待所有操作完成,设置一个统一的超时时间。
getNow
是在结果可用时立即获取结果或在操作尚未完成时获取指定的回退值的正确操作。原则上,在获取TimeoutException
和调用getNow
之间的小时间窗口内,操作可能会完成,但这不会对你的应用逻辑造成任何问题。
关于异常处理,getNow
的行为类似于join()
,在底层操作失败时抛出未检查的CompletionException
,而不是检查的ExecutionException
。如果你不捕获它,它会传播给调用者,这是如果你没有特殊处理此情况的最佳选项。如果等待超时被中断,它将表现得就像你设置了更短的超时时间一样;操作可能已经完成,或者在getNow
时获取回退值。
英文:
If I understand you correctly, you want something like this:
// 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);
First, do not query the results immediately if you want to allow all requests to run in parallel. Then, using allOf
, you can wait for the completion of all operations with a single timeout.
getNow
is the right operation to get the result immediately when available or the specified fall-back value if the operation has not completed yet. In principle, it’s possible that the operation completes in the small time window between getting a TimeoutException
and calling getNow
, but this should not create any problem for your application logic.
Regarding exception handling, getNow
behaves like join()
throwing an unchecked CompletionException
instead of the checked ExecutionException
when the underlying operation failed. If you don’t catch it, it gets propagated to the caller, which is the best option if you have no special handling for this case. If the waiting with timeout got interrupted, it will behave just as if you had a smaller timeout; the operations might have finished already or get the fall-back value at getNow
.
答案2
得分: 0
使用Java 9,您可以使用completeOnTimeout
:
CompletableFuture<ComponentStatusEnum> firstAppStatus = service1.getStatus().completeOnTimeout(ComponentStatusEnum.DOWN, 20, TimeUnit.SECONDS);
更多信息请查看这里。
英文:
With Java 9 you can use completeOnTimeout
:
CompletableFuture<ComponentStatusEnum> firstAppStatus = service1.getStatus().completeOnTimeout(ComponentStatusEnum.DOWN, 20, TimeUnit.SECONDS);
More info here.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论