I have two completionStages method calls that each call a remote service if a condition is not met. They are both pretty long running processes and we need to decrease latency. I also do not care for the secondFuture's response. It could return CompletionStage<Void>
as I only care if the method runs before we exit the main method. An added complexity is that injectedClass2.serviceCall
also throws a really important exception (404 StatusRuntimeException) that needs to be surfaced to the client.
How do I ensure that the first and second future run asynchronously (not dependant on each other) meanwhile the second future surfaces its error codes and exceptions for the client.
Main Method below is my best attempt at this. It works, but I am looking to learn a better implementation that takes advantage of completables/streams,etc.
try {
.
.
.
CompletionStage<Response> firstFuture;
CompletionStage<Response> secondFuture = CompletableFuture.completedFuture(Response.default());
if (condition) {
firstFuture = legacyImplThing.resolve(param1, param2);
} else {
firstFuture =
injectedClass1.longRunningOp(param1, param2);
secondFuture = injectedClass2.serviceCall(param1, param2, someOtherData);
}
final CompletionStage<MainMethodResponse> response =
CompletableFutures.combine(firstFuture, secondFuture, (a, b) -> a)
.thenApply(
v -> ServiceResponse.newBuilder().setParam(v.toString()).build());
handleResponse(response, responseObserver);
} catch (Exception e) {
responseObserver.onError(e);
}
Maybe out of scope, how would one test/check that two completionStages were run concurrently?
EDIT: CompletableFutures.combine()
is a third-party library method and not part of the java.util.concurrent package.