Handling exception using exceptionally on a CompletableFuture - java

I am handling exceptions occurred during the messageProcessingService.processMessage(messageObject) method call using exceptionally method.
Still, the eclipse is asking me to handle the exception at the method call
messageProcessingService.processMessage(messageObject);
The processMessage method throws CheckedException.
Why does this happen? How can I handle it using exceptionally alone
CompletableFuture.supplyAsync(() ->{
return messageProcessingService.processMessage(messageObject);
}).thenAccept(response ->{
if (response.getStatus().equals("OK")) {
log.debug("Sent Message");
deleteMessage(messageObject);
} else {
log.debug("Cannot send Message");
}
}).exceptionally(ex ->{
throw new MessageNotSendException(ex);
});

Related

Exception is not being logged/throwed inside of completable future

I just realised that exception inside of whenComplete, in completable future is not being logged/throwed. Can someone explain that? How to properly use whenComplete?
public static void main(String[] args) {
var c = CompletableFuture.runAsync(() -> {
System.out.println("done");
});
c.whenComplete((unused, throwable) -> {
System.out.println((5/0));
throw new RuntimeException("I am throwing an exception");
});
System.out.println("ok");
}
output of this block of code
done
ok
From the docs (emphasis mine)
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
Description copied from interface: CompletionStage
Returns a new CompletionStage with the same result or exception as this stage, that executes the given action when this stage completes.
When this stage is complete, the given action is invoked with the result (or null if none) and the exception (or null if none) of this stage as arguments. The returned stage is completed when the action returns. If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally.
whenComplete returns a new CompletableFuture. CompletableFuture keeps track of what exception (if any) has occurred and expects you to deal with it. By ignoring the return value, you're suppressing the exception.
To wait on the result of the future, or throw if it throws, use join.
c.whenComplete((unused, throwable) -> {
System.out.println((5/0));
throw new RuntimeException("I am throwing an exception");
}).join();

Execute a list of completable futures only if the previous one throws an exception

I have a list of completable futures and I would like to start with the first future and if there are any completion exceptions, I'd like to try the next future in the list and so on until I exhausted all of my futures. If any of the futures succeed, i'd like to stop there without using the next futures in the list. How do I accomplish this? So far, I have tried this:
for (SampleFutures future : getSampleFutures()) {
try {
return future.someMethod();
} catch (Exception e) {
log.error("An exception occurred, Will try the next future.", e);
}
}
But when I was testing this method, I see that when something fails in the future completion exception is thrown and the next set of futures are not tried.
Edit:
This is how SampleFtures look like
public class SampleFutureA implements SampleFutures {
#Override
public CompletableFuture<SomeOject> someMethod() {
return CompletableFuture
.supplyAsync(() -> someOtherMethod())
.thenApply( ()->anotherMethod())
.exceptionally(ex -> exceptionHandler(ex));
}
This is the kind of issue for which I would recommend using EA Async as it provides a kind of async/await mecanism that makes it very easy to implement this:
Initialize async when your application starts: (you can also pre-process the application, read the documentation for details)
Async.init();
then use await() as follows:
for (SampleFutures future : getSampleFutures()) {
try {
return completedFuture(await(future.someMethod()));
} catch (Exception e) {
log.error("An exception occurred, Will try the next future.", e);
}
}
throw new RuntimeException("All futures failed!");
However, if you cannot or do not want to use it, you can implement the same thing with a recursive asynchronous method:
private CompletableFuture<SomeObject> processNext(Iterator<SampleFutures> iterator) {
if (iterator.hasNext()) {
return iterator.next().someMethod()
.handle((r, e) -> {
if (e != null) {
log.error("An exception occurred, Will try the next future.", e);
return processNext(iterator);
} else {
return completedFuture(r);
}
}).thenCompose(c -> c);
}
CompletableFuture<SomeObject> allFailed = new CompletableFuture<>();
allFailed.completeExceptionally(new RuntimeException("All futures failed!"));
return allFailed;
}
that you call with
return processNext(getSampleFutures().iterator());
This method will call the first future, and only when it fails, it will recursively call itself aynchronously which will call the next ones.
We are unfortunately forced to implement it with hande() + thenCompose(c -> c) because there is no "compose" version of handle() and exceptionally(). So handle() returns a CompletableFuture<CompletableFuture<SampleObject>> and thenCompose() just unwraps it.

How to find CompletableFuture completed execeptionally

I am using CompletableFuture and have a question on exception handling.
I have a code like this, if any of validate() or process() method throws an exception then it is handled by the ExceptionHandler. However when I am using the CompletableFuture like this then the exception thrown is wrapped in CompletionException. May I know how can I make sure that my ExceptionHandler is called there instead of getting CompletionException?
CompletableFuture<Response> response = CompletableFuture
.supplyAsync(() -> {
validationService.validate(request);
return myService.process(request, headers);
});
Before calling get() on CompletableFuture call this method isCompletedExceptionally, will return true if it completes with exception
public boolean isCompletedExceptionally()
Returns true if this CompletableFuture completed exceptionally, in any way. Possible causes include cancellation, explicit invocation of completeExceptionally, and abrupt termination of a CompletionStage action.
You can also add exceptional block for the completableFuture, so while executing task if any exception occurs it will execute the exceptionally with exception an input argument
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> "Success")
.exceptionally(ex->"failed");
In the above example if any exception occurs executing supplyAsync failed will return or else Success is returned
Got it, by calling the following code, it will solve my problem
try {
response.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Throwable impossible) {
throw impossible;
}
}

Can an Exception thrown by something else cancel an async task?

Let's say I have this Java code that does something asynchronously:
public String main() {
try {
// Code before that could throw Exceptions
CompletableFuture.runAsync(() -> {...});
// Code after that could throw Exceptions
} catch (SomeException e) {
// ...
} catch (CompletionException e) {
// ...
}
}
If this were to run and the Async task successfully starts executing, will it still complete even if something else throws an Exception? If not, how can I let the async call finish executing while the Exception gets thrown?
If this were to run and the Async task successfully starts executing, will it still complete even if something else throws an Exception?
yes. The task is not interrupted.
NOTE: If your program exits as a result of an Exception, then the task will be stopped.
If not, how can I let the async call finish executing while the Exception gets thrown?
It does this by default.
If you want to cancel the task however it might ignore the interrupt.
public String main() {
CompletableFuture future = null;
try {
// Code before that could throw Exceptions
future = CompletableFuture.runAsync(() -> {...});
// Code after that could throw Exceptions
} catch (SomeException e) {
if (future != null) future.cancel(true);
// ...
} catch (CompletionException e) {
// ...
}
}
As long as the task has already started, any exceptions thrown after the call to runAsync will not affect that task.
Exceptions propagate up the call stack. A call stack is local to a particular thread. As your task is running asynchronously (i.e. on another thread), there is no way for an exception thrown on another thread to affect it.

java concurrent Future task returning null in case of any exception and not propagating it

I am new to java.util.concurrent package and wrote a simple method which fetches some rows from DB. I made sure that my DB call throws back an exception to handle it. But i am not seeing the exception propagating back to me. Instead call to my method is returning null.
Can some one help me in this case? Here is my sample method call
private FutureTask<List<ConditionFact>> getConditionFacts(final Member member) throws Exception {
FutureTask<List<ConditionFact>> task = new FutureTask<List<ConditionFact>>(new Callable<List<ConditionFact>>() {
public List<ConditionFact> call() throws Exception {
return saeFactDao.findConditionFactsByMember(member);
}
});
taskExecutor.execute(task);
return task;
}
I googled and found some pages around it. But don't see any concrete solutions for it. Experts please help....
The taskExecutor is object of org.springframework.core.task.TaskExecutor
The FutureTask will execute in a new thread and, if an exception occurs, will store it in an instance field. It's only when you'll ask the result of the execution that you will get the exception, wrapped inside an ExecutionException:
FutureTask<List<ConditionFact>> task = getConditionFacts(member);
// wait for the task to complete and get the result:
try {
List<ConditionFact> conditionFacts = task.get();
}
catch (ExecutionException e) {
// an exception occurred.
Throwable cause = e.getCause(); // cause is the original exception thrown by the DAO
}

Categories

Resources