Separate Task Executors used in Spring @Async

In asynchronous processing with @ Async, you can control the number of concurrent executions by doing ThreadPoolTaskExecutor. However, if important processes and less important processes are managed in the same Thread Pool, when a large number of unimportant processes are waiting to be executed, even if you try to execute important processes, it will be difficult to execute. To do.

Therefore, I will divide the TaskExecutor used by the process and manage it in another Thread Pool.

Implementation method

Define two TaskExecutor beans. Both are ThreadPoolTaskExecutors, and the number of concurrent executions is 1.

@SpringBootApplication
@EnableAsync
public class TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(TaskApplication.class, args);
    }

    @Bean
    TaskExecutor importantTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(5);
        return executor;
    }

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(5);
        return executor;
    }
}

The part that performs asynchronous processing is implemented as follows. (Interface omitted) Specify the name of the TaskExecutor used in @ Async. By putting a sleep for 10 seconds in the process, the execution waiting state is generated.

@Service
@Slf4j
public class TaskServiceImpl implements TaskService {

    @Async("importantTaskExecutor")
    @Override
    public void importantTask() {
        try {
            log.info("start important task");
            TimeUnit.SECONDS.sleep(10);
            log.info("end important task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async("taskExecutor")
    @Override
    public void task() {
        try {
            log.info("start normal task");
            TimeUnit.SECONDS.sleep(10);
            log.info("end normal task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

I confirmed the operation with the following code.

@RestController
@RequiredArgsConstructor
public class TaskAsyncController {

    private final TaskService taskService;

    @GetMapping("/")
    public String task() {
        taskService.task();
        taskService.task();
        taskService.task();
        taskService.task();
        taskService.importantTask();

        return "Success!!";
    }
}

When executed, one task method will be executed, but the remaining three will be waiting for execution. However, the importantTask method does not wait for execution and is executed immediately.

Now you can see that another ThreadPoolTaskExecutor is available.

Recommended Posts

Separate Task Executors used in Spring @Async
Annotations used in Spring Boot task management tool
View the Gradle task in the Spring Boot project
Inject Logger in Spring
Use Interceptor in Spring
Microservices in Spring Cloud
Get cookies in Spring