Minute Read: Configuring Task Executor in Spring Boot Application for large operations

Minute Read: Configuring Task Executor in Spring Boot Application for large operations

In this article we will deep dive into how to configure task executors for Spring Boot Application and how they work internally.

Note: Before going through this article you must have basic knowledge of Core Java along with MultiThreading in Spring and Thread Pooling in Java.

The Spring Boot application may need to do some heavy/large operations in some cases such as large file uploading to databases/clouds, downloading large files or exporting bulk amount of data from database into an excel file format.

By default Spring uses SimpleAsyncTaskExecutor to run methods annotated with @Async. But this default configuration of SimpleAsyncTaskExecutor is not recommended generally in production environments for some simple reasons.

  1. The SimpleAsyncTaskExecutor creates a new thread for each new request but it does not reuse them.
  2. Each new thread created by SimpleAsyncTaskExecutor takes upto 1 MB of memory and some processing power. Suppose 10000 calls are made to your API which is doing some sort of large operation then it will create 10000 new threads which are not at all reusable once the task is done and it will cripple your application and maybe even kill it.

For Spring Boot 2.1 x & higher you can create your own TaskExecutor config in your Spring Boot application for handling such large operations.

@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "taskExecutor")
    public AsyncTaskExecutor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(15);
        executor.setQueueCapacity(50);
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }

    @Bean
    public WebMvcConfigurer webMvcConfigurer(AsyncTaskExecutor taskExecutor,
                                                       CallableProcessingInterceptor callableProcessingInterceptor) {
        return new WebMvcConfigurer() {
            @Override
            public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
                configurer.setDefaultTimeout(3600000).setTaskExecutor(taskExecutor);
                configurer.registerCallableInterceptors(callableProcessingInterceptor);
                WebMvcConfigurer.super.configureAsyncSupport(configurer);
            }
        };
    }

    @Bean
    public CallableProcessingInterceptor callableProcessingInterceptor() {
        return new TimeoutCallableProcessingInterceptor() {
            @Override
            public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
                return super.handleTimeout(request, task);
            }
        };
    }
}        


The above code snippet shows the configuration for task executor which needs to be done for your Spring Boot Application. Following are the list of beans created in this configuration class.

  • Task Executor Bean.

In this bean the ThreadPoolExecutor is configured and the Core Pool Size, Max Pool Size and Queue Capacity is set.

Core Pool Size - The core pool size specifies the number of threads to be created for each new request to run the task.

Queue Capacity - The number of new threads is limited to the core pool size specified. If the number of threads exceeds the core pool size then the newly created threads are added in the queue. The queue capacity specifies the number of threads to be added in queue.

Max Pool Size - If the queue is full and number of threads is less than the size defined in max pool size then create a new thread. If the queue is full and number of threads is greater than the max pool size then reject the task.

In this way the ThreadPoolExecutor is configured using these three main properties.


  • Callable Processing Interceptor Bean

The CallableProcessingInterceptor is invoked before and after the invocation of the Callable task in the asynchronous thread. This bean is configured to intercept the concurrent request handling.


  • WebMvcConfigurer Bean

Once the Task Executor & Callable Processing Interceptor Beans are configured then it is necessary to register those beans in our Web MVC using WebMVCConfigurer. The WebMVCConfigurer bean registers both of these beans into the application context along with default timeout in milliseconds to timeout the asynchronous request handling. In this example I have set the default timeout of 3600000 milliseconds which corresponds to 1 hour of default timeout.


In this way we can configure a custom task executor for our Spring Application instead of using Spring 's default SimpleAsyncTaskExecutor for handling large operations in our application in production environments.

Thanks for reading and do subscribe if you wish to see more such content like this.

Thanks again!

要查看或添加评论,请登录

Siddhant Bhandari的更多文章

社区洞察

其他会员也浏览了