I currently have a scheduled task within my Spring application.
However a two parts of this logic is severely time-consuming and I am wondering if there would be a way to make these two parts asynchronous so that it does not interfere with the time of the logic being executed.
The logic that I need to execute as follows.
@Scheduled(fixedDelay = 10000)
public void startAuction() throws Exception {
List<SchGoodsAuctionStartListRes> list = schedulerService.schGoodsAuctionStartList();
for (SchGoodsAuctionStartListRes item : list) {
schedulerService.schGoodsAuctionStart(item);
// 1st time consuming block that needs async
PushInfo pushInfo = pushMapper.pushGoodsSeller(item.getGoodsIdx());
pushInfo.setTitle("Start");
pushInfo.setBody("[" pushInfo.getBrand() "] started.");
pushInfo.setPushGrp("001");
pushInfo.setPushCode("003");
fcmPushUtil.sendPush(pushInfo);
// 2nd time consuming block that needs async
List<PushInfo> pushInfos = pushMapper.pushGoodsAuctionAll(item.getIdx());
for (PushInfo pushInfoItem : pushInfos) {
pushInfoItem.setTitle("\uD83D\uDD14 open");
pushInfoItem.setBody("[" pushInfo.getBrand() "] started. \uD83D\uDC5C");
pushInfoItem.setPushGrp("002");
pushInfoItem.setPushCode("008");
fcmPushUtil.sendPush(pushInfoItem);
}
}
}
From my understanding, a scheduler already is executing logic asynchronously, and I wonder if there would be any way of making those two blocks asynchronous so that it does not cause delays when executing this logic.
Any sort of advice or feedback would be deeply appreciated!
Thank you in advance!
CodePudding user response:
There are several approaches that you could take here.
Configuring Thread Pool executor for Spring's scheduled tasks
By default Spring uses single thread executor to execute scheduled tasks, which means that even if you have multiple @Scheduled
tasks or another execution for a task triggers before the previous one is completed, they will all have to wait in the queue.
You can configure your own executor to be used by Spring Scheduling. Take a look at the documentation of @EnableScheduling
, it is pretty exhaustive on the subject.
To configure ExecutorService
to be used for scheduled tasks it is enough to define a bean:
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(8);
threadPoolTaskScheduler.setThreadNamePrefix("task-scheduler");
return threadPoolTaskScheduler;
}
Additionally, if you use Spring Boot, you can use properties file:
spring.task.scheduling.pool.size=8
Executing scheduled tasks asynchronously
To execute scheduled tasks asynchronously you can use Spring's @Async
annotation (and make sure to @EnableAsync
somewhere in your configuration. That will make your tasks to be executed on a background thread, freeing the scheduling thread.
@EnableAsync
public class ScheduledAsyncTask {
@Async
@Scheduled(fixedRate = 10000)
public void scheduleFixedRateTaskAsync() throws InterruptedException {
// your task logic ...
}
}
Offload expensive parts of your tasks to a different executor
Finally, you could use a separate ExecutorService
and run expensive parts of your tasks using that executor instead of the one used for task scheduling. This will keep the time needed to complete the execution on the thread used by Spring to schedule tasks to a minimum, allowing it to start next executions.
public class ScheduledAsyncTask implements DisposableBean {
private final ExecutorService executorService = Executors.newFixedThreadPool(4);
@Scheduled(fixedRate = 10000)
public void scheduleFixedRateTaskAsync() throws InterruptedException {
executorService.submit(() -> {
// Expensive calculations ...
});
}
@Override
public void destroy() {
executorService.shutdown();
}
}