处理CompletableFuture的get()方法异常。

huangapple go评论59阅读模式
英文:

How to handle exception of CompletableFuture get() method

问题

我需要向第三方网址发送请求,因此我在getStatus()方法上使用了@Async,该方法返回enumCompletableFuture,如果抛出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;
}
我知道这段代码将按顺序执行所以如何在不更改客户端请求超时的情况下以异步方式运行它们
英文:

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&lt;ComponentStatusEnum&gt; status1 = service1.getStatus();
CompletableFuture&lt;ComponentStatusEnum&gt; status2 = service2.getStatus();
CompletableFuture&lt;ComponentStatusEnum&gt; 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&lt;ComponentStatusEnum&gt; firstAppStatus = service1.getStatus().completeOnTimeout(ComponentStatusEnum.DOWN, 20, TimeUnit.SECONDS);

更多信息请查看这里

英文:

With Java 9 you can use completeOnTimeout:

CompletableFuture&lt;ComponentStatusEnum&gt; firstAppStatus = service1.getStatus().completeOnTimeout(ComponentStatusEnum.DOWN, 20, TimeUnit.SECONDS);

More info here.

huangapple
  • 本文由 发表于 2020年7月29日 12:30:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63146360.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定