주기적인 작업 자동화 구축

1. 스케줄링

스케줄링어떤 작업(job)에 대해서 지정된 기간 혹은 시간에 수행하도록 하는 것

 

스프링부트에서 @Scheduled 어노테이션을 이용해서 간단하게 스케줄(배치) 작업을 할 수 있음.

 

2. @Scheduled 사용법

 

2.1 기본 설정

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

 


스케줄링 기능을 이용해서 수행할 Job에 @Scheduled 어노테이션으로 스케줄 시간을 설정

  • 10초 후에 처음으로 job을 수행하고, 매 10초마다 반복 수행
@Service
@Slf4j
public class SchedulerService {

    @Scheduled(initialDelay = 10000, fixedDelay = 10000)
    public void runAfterTenSecondsRepeatEveryTenSeconds() {
        log.info("runAfterTenSecondsRepeatEveryTenSeconds");
    }
}

 

2.2 @Scheduled 옵션

 

1. CRON : 크론 표현식을 이용

// 매 분마다 특정 작업을 5초에 실행
@Scheduled(cron = "5 * * * * *")
public void job() { }

 

2. ZONE : 스케줄링에 사용되는 시간의 타임존을 반영

// 명시적으로 지정한 시간대에 맞춰 작업을 스케줄링
@Scheduled(cron = "5 * * * * *", zone="Asia/Seoul")
public void job() {
}

 

3. fixedDelay / fixedDelayString : 이전 작업이 종료되고 다시 시작되는 시간을 설정

@Scheduled(fiexedDelay=1000L) // 이전 job 완료 후 1초 뒤에 다시 시작
public void job() {
}

 

4. fixedRate / fiexedRateString : 이전 작업의 종료 여부와 상관없이 설정된 시간 간격으로 반복

@Scheduled(fixedRate=1000L) // 매 1초마다 job 수행
public void job() {
}

 

5. initialDelay / initialDelayString : Job을 처음 실행까지 초기 대기 시간 설정

@Scheduled(initialDelay=1000)  // App 실행 완료 후 1초 후에 job이 수행
public void job() {
}

 

 

2.3 @Scheduled 필수 조건

 

cron 표현식, fixedDelay, fixedRate와 같은 실행 주기를 설정하는 옵션을 필수로 한 가지는 적용

@Scheduled 통해 수행되는 job 메서드는 return type이 void 여야 하고, 인자가 없음

 

3. Thread pool

모든 @Scheduled 작업은 Spring에 의해 생성된 한 개의 thread pool에서 실행

  • 하나의 Schedule이 돌고 있다면 그것이 다 끝나야 다음 Schedule이 실행되는 단점이 존재

 

이러한 단점은 스프링 부트에서 설정을 통해 schedule에 대한 thread pool을 생성하고 그 thread pool을 사용하여 모든 스케줄 된 작업을 실행하여 보완할 수 있음

 

💡 생성된 thread pool을 이용하여 여러 개의 스케줄을 동시에 처리

 

@Slf4j
@Configuration
@RequiredArgsConstructor
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);
    }
}

 

4. 스케줄링을 이용하여 영화 정보 업데이트 자동화

 

@Slf4j
@Configuration
@RequiredArgsConstructor
public class SchedulerConfig implements SchedulingConfigurer {

    private final int POOL_SIZE = 10; // 스레드 풀 사이즈
    private final MovieService movieService;

    @Scheduled(initialDelay=1000, fixedDelay=1000*60*60*24) // 24시간 마다 수행
    public void updateMovieList() {
        try {
            movieService.updateMovieList();
            log.info("영화 정보 업데이트 완료");
        } catch (Exception e) {
            throw new GlobalException(GlobalErrorCode._INTERNAL_SERVER_ERROR);
        }
    }

    // 여러 개의 스레드 동시 처리
    @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);
    }
}