在Java中进行多个异步调用时,如何忽略失败的CompletableFuture调用?
我想在Java中使用三个REST服务并行调用,代码如下:在Java中进行多个异步调用时,如何忽略失败的CompletableFuture调用?,java,spring,multithreading,asynchronous,exception,Java,Spring,Multithreading,Asynchronous,Exception,我想在Java中使用三个REST服务并行调用,代码如下: private CompletableFuture < EmployeesListResponse > makeAsyncCall(Request request) { return CompletableFuture.supplyAsync( () -> { try { LOGGER.warn("- - - - - Employees Service async call - - - -
private CompletableFuture < EmployeesListResponse > makeAsyncCall(Request request) {
return CompletableFuture.supplyAsync(
() -> {
try {
LOGGER.warn("- - - - - Employees Service async call - - - - -");
return serviceObj.findServiceImpl(request);
} catch (Exception e) {
LOGGER.warn("service async call failed...", e);
}
return null;
}, asyncExecutor).handle((res, ex) -> {
LOGGER.warn("Exceptionally...", ex.toString(), res.toString());
return new EmployeesListResponse();
});
}
CompletableFuture < EmployeesListResponse > asyncFirstCall = makeAsyncCall(request);
CompletableFuture < EmployeesListResponse > asyncSecondCall = makeAsyncCall(request);
CompletableFuture < EmployeesListResponse > asyncThirdCall = makeAsyncCall(request);
CompletableFuture.allOf(asyncFirstCall, asyncSecondCall, asyncThirdCall).join();
private CompletableFuturemakeAsyncCall(请求){
返回CompletableFuture.SupplySync(
() -> {
试一试{
LOGGER.warn(“----员工服务异步调用-”;
返回serviceObj.findServiceImpl(请求);
}捕获(例外e){
LOGGER.warn(“服务异步调用失败…”,e);
}
返回null;
}句柄((res,ex)->{
LOGGER.warn(“异常…”,例如toString(),res.toString());
返回新员工响应();
});
}
CompletableFutureasyncFirstCall=MakeSyncCall(请求);
CompletableFutureasyncSecondCall=MakeSyncCall(请求);
CompletableFutureasyncThirdCall=MakeSyncCall(请求);
CompletableFuture.allOf(asyncFirstCall、asyncSecondCall、asyncThirdCall).join();
在上面的代码中,我进行了三个调用,并使用CompletableFuture.allOf().join()
加入它们。当所有三个调用的服务响应都为200 OK时,此代码工作正常
如果一个调用失败(500内部服务器错误或404找不到
),而另外两个服务调用200正常,则代码将引发异常,整个API响应将因异常而失败。在这种情况下,我希望忽略一个异常服务调用,并从其他两个调用返回成功响应
在这种情况下,如何处理忽略异常?因此,您试图等待所有3个期货完成后再完成,但当单个期货失败时,所有期货将立即返回。相反,您可以显式地等待以下各项:
List<CompletableFuture<String>> allFutures = Arrays.asList(asyncFirstCall, asyncSecondCall,
asyncThirdCall);
// await completion of all futures
allFutures.forEach(future -> {
try {
future.join();
} catch (CompletionException ex) {
// handled below.
}
});
if (allFutures.stream().filter(CompletableFuture::isCompletedExceptionally).count() > 2) {
throw new RuntimeException("Multiple failures");
}
// else continue with your business logic...
List allFutures=Arrays.asList(asyncFirstCall、asyncSecondCall、,
异步调用);
//等待所有期货交易完成
allFutures.forEach(未来->{
试一试{
future.join();
}catch(CompletionException-ex){
//下面处理。
}
});
if(allFutures.stream().filter(CompletableFuture::isCompletedExceptionally).count()>2){
抛出新的RuntimeException(“多次失败”);
}
//否则请继续您的业务逻辑。。。
您不需要在try-catch块中处理异常,因为您已经在处理handle()方法。无论是否获得异常,每次都将执行此handle()方法。您只需要检查是否存在任何异常,如果是,则根据需要发送默认响应
private CompletableFuture < EmployeesListResponse > makeAsyncCall(Request request) {
return CompletableFuture.supplyAsync(
() -> {
LOGGER.warn("- - - - - Employees Service async call - - - - -");
return serviceObj.findServiceImpl(request);
}, asyncExecutor).handle((res, ex) -> {
if (ex != null) {
LOGGER.warn("Exceptionally...", ex);
return "what ever default you want to return";
// or return new EmployeesListResponse();
}
return res;
});
}
private CompletableFuturemakeAsyncCall(请求){
返回CompletableFuture.SupplySync(
() -> {
LOGGER.warn(“----员工服务异步调用-”;
返回serviceObj.findServiceImpl(请求);
}句柄((res,ex)->{
如果(ex!=null){
记录器。警告(“异常…”,例如);
返回“您想要返回的默认值”;
//或返回新员工响应();
}
返回res;
});
}
如果要忽略,请尝试以下操作
CompletableFuture<Void> allOf = CompletableFuture.allOf(asyncFirstCall,asyncSecondCall);
allOf.whenComplete((aVoid, throwable) -> {
allOf.join();
});
CompletableFuture allOf=CompletableFuture.allOf(asyncFirstCall,asyncSecondCall);
全部完成时((避免,可丢弃)->{
allOf.join();
});
非常感谢!这对于处理异常和从其他成功调用中获得部分响应非常有用。当我等待每个将来加入上面提到的forEach时,restweb服务的响应时间会有延迟吗?因为当我使用allOf()时,响应时间大约是6秒,现在大约是10秒。你能告诉我这是否是代码中潜在的性能问题吗?还有一种方法,我们可以知道异常ex类型是HttpStatusException或ClientErrorException等,以知道错误是404还是500。如果我得到所有的500,那么我必须抛出一个自定义异常,如果其中任何一个是404,那么我必须抛出一个不同的自定义异常,如果其中任何一个是200,我将一如既往地继续。我不会期望有显著的性能差异,可能你只是看到了噪音。当然,除了在失败案例中,你以前失败得更快。通过查看ex.cause()
,您可以检查底层异常的类型。Eclipse IDE正在强制围绕返回serviceObj.findServiceImpl(请求);使用try-catch块,即使我们使用.handle(),所以我使用了try-catch,现在删除了.handle()