My database methods return a CompletableFuture to do the work with database asynchronously and then process the result on the main thread.
public interface IAccountDAO {
CompletableFuture<ObjectId> create(AccountEntity accountEntity);
CompletableFuture<Optional<AccountEntity>> get(String nickname);
CompletableFuture<Void> update(AccountEntity accountEntity);
CompletableFuture<Void> delete(AccountEntity accountEntity);
}
Each of the methods have following code inside (example of get(String)
method):
@Override
public CompletableFuture<Optional<AccountEntity>> get(String nickname) {
return CompletableFuture.supplyAsync(() -> {
try {
// something logic
return Optional.of(...);
} catch (SomethingException ex) {
ex.printStackTrace();
throw new CompletionException(ex);
}
});
}
Handling the result:
CompletableFuture<Optional<AccountEntity>> cf = get("Test_Nickname");
// Notify end user about exception during process
cf.exceptionally(ex -> {
System.out.println("Database operation failed. Stacktrace:");
ex.printStackTrace();
return Optional.ofEmpty(); // I must return something fallback value that passes to downstream tasks.
});
// Downstream tasks that I would to cancel if exception fired
cf.thenAccept(...);
cf.thenRun(...);
cf.thenRun(...);
So, operation with database can fire exception. In this case I would to pass exception and using .exceptionally(...)
or something like this notify the user called that method and STOP chain executing (cancel downstream tasks).
My question is: How I can cancel downstream tasks when CompletableFuture completed with exception?
I don't think you can cancel the downstream tasks.
All you can do is just not execute the downstream tasks incase of exception.
CompletableFuture<Optional<AccountEntity>> cf = get("Test_Nickname");
cf.whenComplete((response, exception) -> {
if (exception == null) {
// Downstream tasks that I would to like to run on this response
} else {
//Notify end user of the exception
}
});
To avoid nesting.
private Response transformResponse(GetResponse r) {
try {
return SuccessResponse();
} catch (Exception e) {
return FailedResponse();
}
}
get("Test_Nickname")
.thenApply(r -> transformResponse(r))
.thenCompose(... //update)