[Spring Boot] @Scheduled 이용한 간단한 스케줄링

Miracle Generator·2021년 11월 4일
3

Spring Boot

목록 보기
4/4

스프링 부트에서 간단하게 스케줄링 해보기

스케줄링은 어떤 작업(job)에 대해서 지정된 기간 혹은 시간에 수행하도록 하는 것이다. 스케줄 작업을 처리하기 위해서는 Quartz Scheduler 와 같은 외부 라이브러리를 이용하거나 스프링부트에서 @Scheduled 어노테이션을 이용해서 간단하게 스케줄(배치) 작업을 할 수 있다.

이 글에서는 스프링 부트에서 @Scheduled 어노테이션을 이용하여 스케줄링을 사용해 보고, 공부한 기록을 남긴다.

@Scheduled 기본 사용법

스프링 부트에서 @Scheduled 를 이용한 스케줄링의 사용은 간단하다.

아래와 같이 Application 클래스에서 @EnableScheduling 어노테이션을 넣어서, 스케줄링 기능을 사용할 수 있는 상태로 만들어 준다.

@EnableScheduling // 스케줄링 기능을 enable 함
@SpringBootApplication
public class AnythingTestApplication {
		...
}

다음으로 아래와 같이 스케줄링 기능을 이용해서 수행할 Job에 @Scheduled 어노테이션으로 스케줄 시간을 설정해 준다.

@Service
@Slf4j
public class SchedulerService {

    @Scheduled(initialDelay = 10000, fixedDelay = 10000)
    public void runAfterTenSecondsRepeatTenSeconds() {
        log.info("10초 후 실행 => time : " + LocalTime.now());
    }
}

위 예제는 프로그램 시작 후, 10초 후에 처음으로 job을 수행하고, 매 10초 마다 반복 수행된다. 결과는 아래와 같이 10초마다 로그가 찍히는 것을 볼 수 있다.

@Scheduled 설정 옵션

@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을 이용하여 여러 개의 스케줄을 동시에 처리할 수 있다.

profile
삶은 나를 만들어가는 과정이다

0개의 댓글