Reputation: 8995
It's my first time working with Async in Spring boot. Here is how my project is structured.
I have the following ExecutorConfig
class
@Configuration
@EnableAsync
public class ExecutorConfig {
@Bean(name = "ConcurrentTaskExecutor")
public Executor getAsyncExecutor() {
return new ConcurrentTaskExecutor(Executors.newFixedThreadPool(10));
}
}
This following class which will be called with @Scheduled
@Component
public class RealtyTracCountyScraper {
@Autowired
StateScrapeQueueRepository stateScrapeQueueRepository;
@Autowired
CountyScrapeRepository countyScrapeRepository;
@Autowired
CountyScraper countyScraper;
// @Scheduled(cron = "0 0 */3 * * *")
@EventListener(ApplicationReadyEvent.class)
public void scrapeCountyLinks() {
System.out.println("Scrape county links ran!");
try {
List<String> stateLinks = stateScrapeQueueRepository.getStatesLinks("");
for (int i = 0; i < stateLinks.size(); i++) {
countyScraper.run(stateLinks.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("---------------------");
}
}
}
and this class which gets called from the class above (This is the class that contains the multithreaded method)
@Component
public class CountyScraper implements AsyncConfigurer {
@Autowired
StateScrapeQueueRepository stateScrapeQueueRepository;
@Autowired
CountyScrapeRepository countyScrapeRepository;
@Async("ConcurrentTaskExecutor")
public void run(String stateLink) {
System.out.println("New thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done");
}
}
Even though I have set 10 fixed threads in the ExecutorConfig
class, it looks like only one thread works at a time. Any idea what I am doing wrong?
Upvotes: 2
Views: 2947
Reputation: 125202
I guess there are a couple of things not completely right in your code.
AsyncConfigurer
@EnableScheduling
Your CountyScraper
implements the AsyncConfigurer
interface. Leading to 2 possible problems. The first is configuring async processing with the defaults and usage of interface based proxies instead of class based proxies. Hence eliminating the @Async
. Although the latter doesn't seem to be the case, one might never know.
The AsyncConfigurer
should actually be implemented by your ExecutorConfig
.
@Configuration
@EnableAsync
@EnableScheduling
public class ExecutorConfig implements AsyncConfigurer {
public Executor getAsyncExecutor() {
return taskExecutor();
}
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new TaskExecutor();
taskExecutor.setCorePoolSize(10);
return taskExecutor;
}
}
This will configure the default Executor
used for async processing. Instead of a ConcurrentTaskExecutor
I used the ThreadPoolTaskExecutor
instead. The latter allows a bit more configuration and will cleanup the threads nicely when Spring Boot shutsdown.
TIP: If you are using Spring Boot 2.1 you can actually ditch the configuration of the TaskExecutor
and replace it with configuration only.
Now you can use a simple @Async
instead of naming the executor explicitly (which will now fail because it is named differently).
spring.task.execution.pool.core-size=10 # Default is 8
Your configuration then becomes
@Configuration
@EnableAsync
@EnableScheduling
public class ExecutorConfig {}
Upvotes: 5