Search code examples
javaspringspring-bootvisualvmreactor

spring boot app consuming all the cpu when AsyncTaskExecutor is configured


I have the following configuration in my Spring Boot app:

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig {
    private static final int BUFFER = 1024;

    @Bean
    public AsyncTaskExecutor singleThreadAsyncTaskExecutor(Environment env) {
        RingBufferAsyncTaskExecutor rbAsyncExecutor = new RingBufferAsyncTaskExecutor(env);
        rbAsyncExecutor.setName("rb-executor");
        rbAsyncExecutor.setBacklog(BUFFER);
        rbAsyncExecutor.setProducerType(ProducerType.SINGLE);
        rbAsyncExecutor.setWaitStrategy(new YieldingWaitStrategy());

        log.info("Async task executor loaded");
        return rbAsyncExecutor;
    }
}

when I run it, the cpu usage hits 100% (sometimes 100 something):

enter image description here

investigating with visualvm, I see this

enter image description here

but, when I remove the instantiation of AsyncTaskExecutor the CPU usage goes to 0.4% and the visualvm shows me barely 1% of CPU usage.
I found this problem while deploying it with docker, I saw my host usage hit the ceiling.
I tried lower the buffer size (it was 2048) to 1024 but nothing changed.
Without this bean, my @Async services doesn't work asynchronously. (No TaskExecutor bean found for async processing)


Solution

  • I think I solved.
    What I did was use ThreadPoolTaskExecutor instead RingBuffer, as follows

    @Bean
    public AsyncTaskExecutor getAsync(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(7);
        executor.setMaxPoolSize(42);
        executor.setQueueCapacity(11);
        executor.setThreadNamePrefix("AsyncExec-");
        executor.initialize();
        return executor;
    }
    

    for some reason, the ThreadPoolTaskExecutor is lighter than others.
    I got this from spring framework doc