본문 바로가기

스프링/Spring

[SpringBoot] 스프링부트에서 스케쥴러 사용하기

Schedule의 사전적 정의는 "일정[시간 계획]을 잡다"라는 뜻입니다.

Spring Boot를 통해 Spring에서 지원하는 스케줄러를 간편하게 작성할 수 있습니다.

Schedule 기능 켜기

자바 설정(Java configuration) 관련 클래스에 @EnableScheduling를 추가하면 스케쥴링 기능을 사용할 수 있습니다.

@EnableScheduling
@SpringBootApplication
public class SchedulerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SchedulerApplication.class, args);
    }

}

구현하기

@Scheduled 어노테이션을 메소드에 선언하며 작업을 실행이 가능하며, 실행 주기는 cron, fixedDelay, fixedRate 라는 세 개의 속성으로 지정할 수 있습니다.

cron으로 실행 주기 설정하기

그 전에 crontab 주기 설정 방법부터 알아보겠습니다.

*           *      *      *      *      *
초(0-59)    분(0-59) 시간(0-23) 일(1-31)  월(1-12) 요일(0-7) 
각 별 위치에 따라 주기를 다르게 설정 할 수 있습니다.
순서대로 초-분-시간-일-월-요일 순이다. 그리고 괄호 안의 숫자 범위 내로 별 대신 입력 할 수 있습니다.
요일에서 0과 7은 일요일이고, 1부터 월요일이고 6이 토요일입니다.

 

1분마다 특정 작업이 실행되도록 스케줄을 설정합니다. 1분마다 호출되고, 이 시간은 이전 호출이 완료된 시점부터 계산됩니다.

@Scheduled(cron = "1 * * * * ?")
public void cronJobSch() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        Date now = new Date();
        String strDate = sdf.format(now);
        System.out.println("작업 날짜 시간:: " + strDate);

}

 

fixedDelay로 실행 주기 설정하기

다음 예제도 1초마다 호출되고, 이 시간은 이전 호출이 완료된 시점부터 계산됩니다.

@Scheduled(fixedDelay = 1000)
public void scheduleFixedDelayTask() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        Date now = new Date();
        String strDate = sdf.format(now);
        System.out.println("작업 날짜 시간 fixedDelay:: " + strDate);
}

 

fixedRate로 실행 주기 설정하기

고정된 비율로 실행하기를 원한다면 fixedRate를 사용하면 됩니다.

다음 예제는 각 호출의 연속적인 시작 시각의 간격으로 계산된 1초마다 실행됩니다.

@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        Date now = new Date();
        String strDate = sdf.format(now);
        System.out.println("작업 날짜 시간 fixedRate::" + strDate);
}
fixedDelay와 fixedRate의 delay 하기 시작하는 시점입니다.
fixedDelay는 이전 수행이 종료된 시점부터 delay후에 재호출 되고, fixedRate는 이전 수행이 시작된 시점부터 delay후에 재호출 됩니다. 그러므로 fixedRate로 지정 시 작업이 동시에 여러 개가 돌 가능성이 존재합니다.

 

 

Thread pool 설정

기본적으로 모든 @Scheduled 작업은 Spring에 의해 생성된 한 개의 스레드 풀에서 실행됩니다.

실제로 로그를 보면 같은 쓰레드로 확인될 것이다.

System.out.println("현재 쓰레드 : "+ Thread.currentThread().getName());

결과

현재 쓰레드 : scheduling-1

 

문제 상황

한 개의 스레드 풀에서 실행되기 때문에 하나의 Scheduled이 돌고 있다면 그것이 다 끝나야 다음 Scheduled이 실행되는 문제가 있습니다.

다음 예시에서 우리는 1초마다 실행 되기를 바랐지만, 3초나 걸리는 작업이 있기 때문에 1초마다 작업이 실행이 안 되는 것을 알 수 있습니다.

@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        Date now = new Date();
        String strDate = sdf.format(now);
        System.out.println("작업 날짜 시간 fixedRate::" + strDate);
        System.out.println("현재 쓰레드 : "+ Thread.currentThread().getName());

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}

 

스케쥴링 설정 클래스를 사용한 쓰레드 풀 설정

스프링 부트에서 설정을 통해 Schedule에 대한 쓰래드 풀을 생성하고 그 쓰레드 풀을 사용하여 모든 스케줄 된 작업을 실행하도록 할 수 있습니다.

아래는 스레드 풀 사이즈를 10개로 설정한 예시입니다.

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
    private final int POOL_SIZE = 10;
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();

        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool");
        threadPoolTaskScheduler.initialize();

        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

스케줄이 돌고있는 메서드에서 현재 쓰레드의 이름을 로깅하면 아래와 같은 출력이 표시됩니다.

 

소스코드 보기

https://github.com/keepseung/SpringBoot-Blog-Source/tree/main/scheduler

 

GitHub - keepseung/SpringBoot-Blog-Source: 스프링 부트를 사용해 어플리케이션을 만들때 필요한 기능들을

스프링 부트를 사용해 어플리케이션을 만들때 필요한 기능들을 담고 있습니다. . Contribute to keepseung/SpringBoot-Blog-Source development by creating an account on GitHub.

github.com