Exception handling for CompletatbleFuture<Void> when used with Spring's Async

688 views Asked by At

I am quite new to this completable future concept. I am using Spring's async annotation and for this I have added a file configuration for executor and exception handler as follows:

@Override
public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
    taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
    taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
    taskExecutor.setThreadNamePrefix("AsyncThread - ");
    taskExecutor.initialize();
    return taskExecutor;
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return asyncExceptionHandler;
}

And then I have a method which I want to run asynchronously and return CompletableFuture :

@Async
public CompletableFuture<Void someMethod() {
     try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return CompletableFuture.completedFuture(null);
}

Now if some exception happens in the above method call, then how should I handle the exception here?

Note: If I don't return CompletableFuture and return void instead, it will go to the exception handler AsyncUncaughtExceptionHandler, but as per my requirement I want to return CompletableFuture Void.

1

There are 1 answers

0
badger On

It is the expected behavior. take a look at AsyncExecutionAspectSupport class method handleError:

protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
    if (Future.class.isAssignableFrom(method.getReturnType())) {
        ReflectionUtils.rethrowException(ex);
    }
    else {
        // Could not transmit the exception to the caller with default executor
        try {
            this.exceptionHandler.obtain().handleUncaughtException(ex, method, params);
        }
        catch (Throwable ex2) {
            logger.warn("Exception handler for async method '" + method.toGenericString() +
                    "' threw unexpected exception itself", ex2);
        }
    }
} 

If the method return type be a variant of Future then always if (Future.class.isAssignableFrom(method.getReturnType())) evaluates to true and the exception is re-thrown to be handled by the higher level caller, so it is not handled by AsyncUncaughtExceptionHandler.

You can handle the exception by the facilities provided to you by CompletableFuture such as handle(BiFunction<? super T, Throwable, ? extends U> fn) method or use try/catch block.