Reputation: 149
I want to consume three REST service parallel calls in Java and my code is as below:
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();
In the above code, I am making three calls and joining them using CompletableFuture.allOf().join()
. This code is working perfectly fine when the service response is 200 OK for all the three calls.
If one call fails(500 Internal Server Error or 404 Not Found
) and other two service calls are 200 OK, then the code is throwing exception and the entire API response is getting failed with an exception. In this case, i want to ignore one service call with exception and return success response from the other two calls.
How to handle to ignore an exception in this scenario ?
Upvotes: 3
Views: 4528
Reputation: 302
If you want to ignore, try like below
CompletableFuture<Void> allOf = CompletableFuture.allOf(asyncFirstCall,asyncSecondCall);
allOf.whenComplete((aVoid, throwable) -> {
allOf.join();
});
Upvotes: 0
Reputation: 146
You don't need to handle the exception in try catch block as you are already handling handle() method. No matter you get the exception or not but this handle() method will execute every time. you just need to check if is there any exception if yes send default response as you want.
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;
});
}
Upvotes: 0
Reputation: 9013
So you're trying to wait for all 3 futures to complete before finishing, but the allOf
future returns immediately when a single one fails. Instead you can explicitly wait on each:
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...
Upvotes: 3