보통 스프링에서 주기적으로 동작하는 로직이 있는경우 @Scheduled를 사용해서 특정시간 또는 날짜에 그 로직을 작동시키는 행동을 합니다.
하지만 그 로직이 오래걸릴 경우 해당 로직 종료전에 스케줄 시간이 다시 올경우 그 스케줄은 동작하지 않습니다. 왜냐하면 해당 스케줄러가 싱글 쓰레드로 동작하기 때문입니다.
기본적으로 Spring은 Single Thread Executor를 사용합니다. 따라서 두 개의 @Scheduled 작업이 겹치지 않습니다. 완전히 관련 없는 클래스에 있는 두 개의 @Scheduled 메서드도 모든 @Scheduled 작업을 실행하는 단일 스레드만 있기 때문에 겹치지 않습니다 .
또한 기본 Executor를 스레드 풀 기반 실행기로 교체하더라도 이러한 Executor는 일반적으로 이전에 예약된 인스턴스가 완료될 때까지 작업 인스턴스의 실행을 지연합니다. 이는 fixedDelay, fixedInterval 및 cron 기반 일정에 해당됩니다. 예를 들어 이 스프링 구성은 스레드 풀을 사용하는 ScheduledThreadPoolExecutor를 생성 하지만 원하는 대로 동일한 일정의 동시 인스턴스를 허용하지 않습니다.
따라서 아래와 같이 빈을 생성하여 별도로 설정을 해야합니다.
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(8);
threadPoolTaskScheduler.setThreadNamePrefix("task-scheduler");
return threadPoolTaskScheduler;
}
그리고 해당 스케줄에는 아래와 같이 어노테이션을 추가합니다.
@EnableAsync
public class ScheduledAsyncTask {
@Async
@Scheduled(fixedRate = 10000)
public void scheduleFixedRateTaskAsync() throws InterruptedException {
// your task logic ...
}
}
또 다른 방법으로는 아예 ExecutorService를 분리하는 방법입니다.
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();
}
}
실제 프로그램에서는 @Bean이 관리할 수 있게 하는것이 좀 더 좋은것 같습니다.
[Kotlin] Switch 문 대신에 When으로 조건문 사용하기 (0) | 2023.03.07 |
---|---|
[Spring/Kotlin] 스케줄 설정 하기 - Schedule / Cron (0) | 2023.03.07 |
댓글 영역