Web/spring

[Task Execution and Scheduling] @Scheduled annotation

태애니 2023. 11. 22. 23:47
728x90

 

@Scheduled 애노테이션을 이용하면 아주 쉽게 메소드 추가가 가능하다

 

 

@EnableScheduling // 스케줄링
@SpringBootApplication
public class AnythingTestApplication {
		...
}

 

 

다음 메서드는 고정된 지연 시간을 두고 5초(5000밀리초)마다 호출됩니다. 즉, 기간은 각 이전 호출의 완료 시간부터 측정된다.

@Scheduled(fixedDelay = 5000)
public void doSomething() {
	// something that should run periodically
}

 

 

 

 

https://velog.io/@kenux/Spring-Boot-Scheduled-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81

 

[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 매월 첫 번째 월요일 자정

 

728x90