[Task Execution and Scheduling] @Scheduled annotation
@Scheduled 애노테이션을 이용하면 아주 쉽게 메소드 추가가 가능하다
@EnableScheduling // 스케줄링
@SpringBootApplication
public class AnythingTestApplication {
...
}
다음 메서드는 고정된 지연 시간을 두고 5초(5000밀리초)마다 호출됩니다. 즉, 기간은 각 이전 호출의 완료 시간부터 측정된다.
@Scheduled(fixedDelay = 5000)
public void doSomething() {
// something that should run periodically
}
[Spring Boot] @Scheduled 이용한 간단한 스케줄링
스케줄링은 어떤 작업(job)에 대해서 지정된 기간 혹은 시간에 수행하도록 하는 것이다. 스케줄 작업을 처리하기 위해서는 Quartz Scheduler 와 같은 외부 라이브러리를 이용하거나 스프링부트에서 @S
velog.io
@Scheduled 어노테이션에 설정할 수 있는 옵션은 아래와 같다.
- cron : 크론 표현식을 이용하여 스케줄링한다.
@Scheduled(cron = "5 * * * * *")
public void something() {
}
- zone : 스케줄링에 사용되는 시간의 타임존을 반영한다.
@Scheduled(cron = "5 * * * * *", zone="Asia/Seoul")
public void something() {
}
- fixedDelay / fixedDelayString: 이전 작업이 종료되고 다시 시작되는 시간을 설정한다.
@Scheduled(fiexedDelay=1000L) // 이전 something() 수행 완료 후 1초 뒤에 다시 시작
public void something() {
}
- fixedRate / fiexedRateString : 이전 작업의 종료 여부와 상관없이 설정된 시간 간격으로 반복한다.
@Scheduled(fixedRate=1000L) // 매 1초마다 something() 수행
public void something() {
}
fixedDelay와 차이가 있으므로 잘 구분해서 사용하도록 하자.
- initialDelay / initialDelayString : Job을 처음 실행까지 초기 딜레이(대기) 시간 설정
@Scheduled(initialDelay=1000) // App 실행 완료 후 1초 후에 something 잡이 수행됨.
public void something() {
}
@Schedule 적용 필수 조건
- cron 표현식, fixedDelay, fixedRate 와 같은 실행 주기를 설정하는 옵션을 필수로 한 가지는 적용해야 한다.
- @Scheduled 통해 수행되는 job 메소드는 return type이 void 여야하고, parmeter를 줄 수 없다는 제약이 있다.
Thread pool 활용
모든 @Scheduled 작업은 Spring에 의해 생성 된 한 개의 thread pool에서 실행된다. 그래서 하나의 Schedule이 돌고 있다면 그것이 다 끝나야 다음 Schedule이 실행되는 단점이 있다.
아래와 같이 예제를 만들어서 1초마다 실행되는 로그를 살펴보면 스케줄이 실행되는 thread를 확인할 수 있다.
@Scheduled(fixedRate = 1000)
public void runEveryTenSecondsOne() {
log.info("runEveryTenSecondsOne time : " + LocalTime.now());
log.info("runEveryTenSecondsOne thread: " + Thread.currentThread().getName());
}
@Scheduled(fixedRate = 1000)
public void runEveryTenSecondsTwo() {
log.info("runEveryTenSecondsTwo time : " + LocalTime.now());
log.info("runEveryTenSecondsTwo thread: " + Thread.currentThread().getName());
}
실제로 로그를 보면 같은 쓰레드로 확인 될 것이다.
이러한 단점은 스프링 부트에서 설정을 통해 schedule에 대한 thread pool을 생성하고 그 thread pool을 사용하여 모든 스케줄 된 작업을 실행하여 보완할 수 있다.
아래는 설정 방법에 대한 예제이다.
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("test-scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
스케줄이 돌고있는 메소드에서 현재 스레드의 이름을 로깅하면 아래와 같은 출력이 표시된다.
생성된 thread pool을 이용하여 여러 개의 스케줄을 동시에 처리할 수 있다.
크론 표현의미
0 0 * * * * | 매일 매시간 정상 |
*/10 * * * * * | 10초마다 |
0 0 8-10 * * * | 매일 8시, 9시, 10시 |
0 0 6,19 * * * | 매일 오전 6시, 오후 7시 |
0 0/30 8-10 * * * | 매일 8:00, 8:30, 9:00, 9:30, 10:00, 10:30 |
0 0 9-17 * * MON-FRI | 평일 9시부터 5시까지 |
0 0 0 25 DEC ? | 매년 크리스마스 자정 |
0 0 0 L * * | 매월 마지막 날 자정 |
0 0 0 L-3 * * | 매월 3~말일 자정 |
0 0 0 * * 5L | 매월 마지막 금요일 자정 |
0 0 0 * * THUL | 매월 마지막 목요일 자정 |
0 0 0 1W * * | 매월 첫째 주 평일 자정 |
0 0 0 LW * * | 매월 마지막 주 평일 자정 |
0 0 0 ? * 5#2 | 매월 두 번째 금요일 자정 |
0 0 0 ? * MON#1 | 매월 첫 번째 월요일 자정 |