I've got the following controller advice:
@ControllerAdvice
public class ExceptionHandlerAdvice {
@ExceptionHandler(NotCachedException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ModelAndView handleNotCachedException(NotCachedException ex) {
LOGGER.warn("NotCachedException: ", ex);
return generateModelViewError(ex.getMessage());
}
}
It works great most of the time but when the NotCachedException is thrown from a method annotated with @Async, the exception is not handled properly.
@RequestMapping(path = "", method = RequestMethod.PUT)
@Async
public ResponseEntity<String> store(@Valid @RequestBody FeedbackRequest request, String clientSource) {
cachingService.storeFeedback(request, ClientSource.from(clientSource));
return new ResponseEntity<>(OK);
}
Here is the config of the Executor:
@SpringBootApplication
@EnableAsync
public class Application {
private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
SettingsConfig settings = context.getBean(SettingsConfig.class);
LOGGER.info("{} ({}) started", settings.getArtifact(), settings.getVersion());
createCachingIndex(cachingService);
}
@Bean(name = "matchingStoreExecutor")
public Executor getAsyncExecutor() {
int nbThreadPool = 5;
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(nbThreadPool);
executor.setMaxPoolSize(nbThreadPool * 2);
executor.setQueueCapacity(nbThreadPool * 10);
executor.setThreadNamePrefix("matching-store-executor-");
executor.initialize();
return executor;
}
}
What can I do in order to make it work with @Async annotated methods?
The default exception handling machenism does not work in case of @Async Enabled. To handle exception thrown from methods annotated with @Async, you need to implement a custom AsyncExceptionHandler as.
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler{
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// Here goes your exception handling logic.
}
}
Now You need to configure this customExceptionHandler in you Application class as
@EnableAsync
public class Application implements AsyncConfigurer {
@Override Executor getAsyncExecutor(){
// your ThreadPoolTaskExecutor configuration goes here.
}
@Override
public AsyncUncaughExceptionHandler getAsyncUncaughtExceptionHandler(){
return new AsyncExceptionHandler();
}
Note: Make sure in order to make your AsyncExceptionHandler work you need to implement AsyncConfigurer in your Application class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With