Why doesn't completeable future logs exception?

Viewed 356

While working with CompletableFuture in spring boot application, I noticed that there was an exception occurring in function which is ran Async using CompletableFuture, but there was nothing logs. The function execution stopped and hence CompletableFuture was completed. Why was there nothing in logs? When I used .whenComplete with .runAsync, I was able to log the error.

void function() {
   CompletableFuture
     .runAsync(() -> runAsyncfunction())
     .whenComplete((result, err) -> {//log the error})
 }

EDIT: If I don't use the .whenComplete the JVM doens't print the stack trace of uncaught exception occuring in runAsyncfunction automatically. But If I use .whenComplete I can log the exception.

Also, is it good industry practice to use .whenComplete in such scenario ?

1 Answers

"The JVM" does not print exception stack traces of its own free will. You need to write code that makes it happen. About the only case I can think of where it might appear that happens is if an exception escapes out of main(). Otherwise, code you wrote or code you called has explicit instructions to print out a stack trace. Maybe if your code is called from some Spring Boot code, the Spring Boot code has an exception handler to do that for you - I don't know, I don't use it.

In this case

someFuture.runAsync(() -> runAsyncfunction());

at the time you call someFuture.runAsync(), you will be returned a new CompletableFuture, which you have ignored.

When someFuture completes, your runAsyncFunction() will execute, likely in some other thread. If that throws an exception, the 'future that you ignored' will complete exceptionally. But you'll never find out about it, because you ignored the mechanism that would have told you.

To summarize: some exception was thrown in some other thread, the thread running the async routine. That exception was caught there, and used to "complete the future exceptionally". But you need to do something to find out that the future was completed; it's just unexamined status information in the future until you do.

This construction:

someFuture.runAsync(() -> runAsyncfunction())
          .whenComplete(blah blah);

is equivalent to

CompletableFuture<Void> x =
    someFuture.runAsync(() -> runAsyncfunction());
x.whenComplete(blah blah);

Perhaps that makes it clearer what is going on in that case. 'runAsync' fails, 'x' is completed exceptionally. The whenComplete then fires, and you can do something useful with the failure.


Footnote: the code as posted looks invalid to me.

CompletableFuture
   .runAsync(() -> runAsyncfunction())
   .whenComplete((result, err) -> {//log the error})

so I hope I divined your intent correctly.

Related