Spring Boot @Async method in controller is executing synchronously
You are calling the @Async
method from another method in the same class. Unless you enable AspectJ proxy mode for the @EnableAsync
(and provide a weaver of course) that won't work (google "proxy self-invocation"). The easiest fix is to put the @Async
method in another @Bean
.
For all those who are still looking for all the steps in @Asnyc explained in a simple way, here is the answer:
Here is a simple example with @Async. Follow these steps to get @Async to work in your Spring Boot application:
Step 1: Add @EnableAsync annotation and Add TaskExecutor Bean to Application Class.
Example:
@SpringBootApplication@EnableAsyncpublic class AsynchronousSpringBootApplication { private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class); @Bean(name="processExecutor") public TaskExecutor workExecutor() { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setThreadNamePrefix("Async-"); threadPoolTaskExecutor.setCorePoolSize(3); threadPoolTaskExecutor.setMaxPoolSize(3); threadPoolTaskExecutor.setQueueCapacity(600); threadPoolTaskExecutor.afterPropertiesSet(); logger.info("ThreadPoolTaskExecutor set"); return threadPoolTaskExecutor; } public static void main(String[] args) throws Exception { SpringApplication.run(AsynchronousSpringBootApplication.class,args); }}
Step 2: Add Method which executes an Asynchronous Process
@Servicepublic class ProcessServiceImpl implements ProcessService { private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class); @Async("processExecutor") @Override public void process() { logger.info("Received request to process in ProcessServiceImpl.process()"); try { Thread.sleep(15 * 1000); logger.info("Processing complete"); } catch (InterruptedException ie) { logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage()); } }}
Step 3: Add an API in the Controller to execute the asynchronous processing
@Autowiredprivate ProcessService processService;@RequestMapping(value = "ping/async", method = RequestMethod.GET) public ResponseEntity<Map<String, String>> async() { processService.process(); Map<String, String> response = new HashMap<>(); response.put("message", "Request is under process"); return new ResponseEntity<>(response, HttpStatus.OK); }
I have also written a blog and a working application on GitHub with these steps. Please check: http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html
I had a similar issue and I had the annotations @Async and @EnableAsync in the correct beans and still the method was executing synchronously. After I checked the logs there was a warning saying that I had more than one bean of type ThreadPoolTaskExecutor and none of them called taskExecutor So...
@Bean(name="taskExecutor")public ThreadPoolTaskExecutor defaultTaskExecutor() { ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); //Thread pool configuration //... return pool;}
See http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html for the configuration available for the thread pool.