본문 바로가기
Spring

@Scheduled 어노테이션을 이용한 스케줄링

by hseong 2023. 4. 30.

https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-annotation-support

스프링은 @Scheduled 어노테이션을 이용하여 스케줄링에 대한 지원을 제공합니다.

 

@Configuration 클래스에 @EnableScheduling 어노테이션을 추가함으로써 @Scheduled 어노테이션을 활성화 할 수 있습니다.

@EnableScheduling
@Configuration
public class AppConfig {
}

메서드에 @Scheduled 어노테이션을 추가하여 원하는 작업을 반복적으로 호출할 수 있습니다.

fixedDelay

@Scheduled(fixedDelay = 1000)
public void helloWorld() {
    System.out.println("Hello, World!");
}

fixedDelay는 메서드의 작업 끝난 후 일정 시간 뒤 다시 메서드를 실행합니다.

작업이 종료되는 시간에 따라서 메서드 호출 간격에 차이가 발생할 수 있습니다.

fixedRate

@Scheduled(fixedRate = 1000)
public void helloWorld() {
    System.out.println("Hello, Wolrd!");
}

fixedRate는 메서드를 실행하고 일정 시간이 지난 뒤 메서드를 다시 실행합니다.

이전 작업의 종료 여부와 관계 없이 지정한 간격에 따라 실행됩니다.

 

fixedDelay와 fixedRate의 단위는 기본적으로 밀리초(ms) 단위입니다. 단위를 바꾸고 싶을 경우에는 timeUnit 속성을 사용하여 변경이 가능합니다.

cron

@Scheduled(cron = "*/10 * * * * *")
public void cron() {
    System.out.println("this is cron");
}

특정 주기, 특정 시간마다 실행시키고자 할 때 cron 속성을 이용할 수 있습니다.

"초 분 시간 일 월 년" 순으로 크론 표현식을 이용하여 반복할 주기를 지정할 수 있습니다. 위 메서드는 10초마다 반복 수행됩니다.

크론 표현식에 대한 예시는 아래 링크에서 확인할 수 있습니다.

https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-cron-expression

 

실습

스케줄링 작업을 수행하던 중에 쓰레드가 bolck 되는 상황이 발생한다고 가정해보겠습니다.

@Scheduled(fixedRate = 1000)
public void fixedRate() throws InterruptedException {
    System.out.println(
            LocalDateTime.now().format(formatter)
            + " - fixedRate: "
            + Thread.currentThread().getName());
    Thread.sleep(5000);
}

위 작업은 fixedRate 속성을 사용하여 작업 수행 시간과 관계없이 1초마다 해당 작업이 수행되기를 기대하고 있습니다.

그러나 기대와는 달리 메서드의 작업시간인 5초가 지난 후에야 다시 작업이 수행됩니다. 이를 해결하기 위해서는 해당 작업이 비동기적으로 수행되어야 합니다.

@Async

공식문서에서는 @Scheduled 어노테이션과 함께 @Async 어노테이션에 대해서도 설명하고 있습니다. 해당 어노테이션을 통해서 스케줄링 작업이 비동기적으로 이루어지게 설정합니다.

@EnableAsync
@EnableScheduling
@Configuration
public class AppConfig {

 

@Async
@Scheduled(fixedRate = 1000)
public void fixedRate() throws InterruptedException {
    System.out.println(
            LocalDateTime.now().format(formatter)
            + " - fixedRate: "
            + Thread.currentThread().getName());
    Thread.sleep(5000);
}

@EnableAsync 어노테이션을 @Configuration 클래스에 추가합니다. 그리고 비동기 수행이 이루어지길 원하는 메서드에 @Async 어노테이션을 추가해줍니다.

각 작업은 백그라운드 쓰레드에서 실행되어 기대한대로 1초마다 작업의 반복 수행이 이루어지게 됩니다.

ScheulingConfigurer

 

EnableScheduling (Spring Framework 6.0.8 API)

Enables Spring's scheduled task execution capability, similar to functionality found in Spring's XML namespace. To be used on @Configuration classes as follows: @Configuration @EnableScheduling public class AppConfig { // various @Bean definitions } This e

docs.spring.io

스프링 컨텍스트에 TaskScheuler를 직접 bean으로 등록해놓지 않았다면, 단일 쓰레드를 가진 디폴트 스케줄러를 만들고 등록된다고 합니다. 

@EnableScheduling
@Configuration
public class AppConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(2);
    }
}

만일 스케줄링 작업을 수행하는 쓰레드의 갯수를 늘리고 싶다면 위와 같은 방법으로 쓰레드 풀 사이즈를 늘릴 수 있습니다. 위는 공식문서의 예제에 따라 스케줄러의 풀 사이즈를 2개로 늘린것입니다.