I am working with a Spring boot application. I have a rest controller that returns Callable.
@GetMapping("/fb-roles")
@Timed
public Callable<List<FbRole>> getAllFbRoles() {
log.debug("REST request to get all FbRoles");
return (() -> { return fbRoleRepository.findAll(); });
}
A ThreadPoolTaskExecutor is configures as follow:
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
private final JHipsterProperties jHipsterProperties;
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("fb-quiz-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
2018-09-19 00:43:58.434 WARN 10104 --- [ XNIO-2 task-28] o.s.w.c.request.async.WebAsyncManager : !!! An Executor is required to handle java.util.concurrent.Callable return values. Please, configure a TaskExecutor in the MVC config under "async support". The SimpleAsyncTaskExecutor currently in use is not suitable under load.
But while accessing the api server is producing the following warning
Spring configuration is a bit confusing in this respect, since it requires separate configuration for MVC Async support, i.e. using a Controller handler method that returns a Callable
, and for any Spring bean method annotated with @Async
. To configure both of it correctly you can apply something like the configuration below keeping in mind that the AsyncTaskExecutor
config might need amending:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Bean
protected WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setTaskExecutor(getTaskExecutor());
}
};
}
@Bean
protected ConcurrentTaskExecutor getTaskExecutor() {
return new ConcurrentTaskExecutor(Executors.newFixedThreadPool(5));
}
}
On a side note, you might feel tempted to simply annotate your Controller handler method with @Async
. This will only have the desired effect - freeing up web server threads - on fire and forget operations (this observation is based on Spring Boot 2.1.2, possibly they will address this in the future). If you want to leverage the power of Servlet 3.0 Asynchronous Processing, you really have to use Callables
and configure them with a WebMvcConfigurer
.