A microservice of ours is calling an endpoint of a partner microservice. But because of changes in the partner microservice, now the result, that was provided by one endpoint, will be provided, when calling two different endpoints. That is why I have to separate the call into two calls and combine the results.
So I defined two methods:
@Async("executor")
public CompletableFuture<List<DashboardItem>> getDashboardItemsFuture1()
@Async("executor")
public CompletableFuture<List<DashboardItem>> getDashboardItemsFuture2()
and inside each of these methods I execute a rest call and provide the result to the CompletableFuture instance like this:
@Async("executor")
public CompletableFuture<List<DashboardItem>> getDashboardItemsFuture1() {
return CompletableFuture.completedFuture(executeRestCall())
}
And I would like to combine the results from the two CompletableFutures in a way that :
- It is waited till all the REST calls end their execution.
- If one of the REST calls execution throws Exception (for example TimeoutException) still the result of the other REST call is returned from our microservice.
So my code for this logic is :
var dashboardItemsFuture1 = getDashboardItemsFuture1();
var dashboardItemsFuture2 = getDashboardItemsFuture1()
var combinedFuture = CompletableFuture.allOf(dashboardItemsFuture1, dashboardItemsFuture2);
try {
combinedFuture.get(); // Wait for both futures to complete
} catch (Exception exc) {
// Handle exceptions
log.error(exc);
}
Optional.ofNullable(dashboardItemsFuture1.get())
.ifPresent(dashboardItems::addAll);
Optional.ofNullable(dashboardItemsFuture2.get())
.ifPresent(dashboardItems::addAll);
But obviously this will not work, as when I simulated in a UnitTest throwing an Exception during the REST call of the first CompletableFuture, the Exception was thrown only at this line:
var dashboardItemsFuture1 = getDashboardItemsFuture1();
So - what is the correct way to combine the two CompletableFutures in the way that I want?
If I understand well your problem then you can use
exceptionnally: