[SpringBoot] Spring Scheduler 적용하기

다은·2025년 6월 4일
1

SpringBoot

목록 보기
8/12

노약자를 위한 AI 말동무 서비스, POPPET 서비스의 개발 일대기입니다.
스케쥴링을 통해 주기적으로 사용자에게 이메일을 전송하는 기능을 구현했습니다.

👇 이메일 전송 관련 포스트 👇
https://velog.io/@dooo_it_ly/SpringBoot-JavaMailSender을-이용한-비동기-이메일-발송-기능-구현


Spring Scheduler은 Spring Framework의 일부로, 정해진 주기에 태스크를 수행하는 기능을 구현할 때 유용한 기능입니다. Spring Scheduler를 사용하는 방법과 쓰레드풀을 커스텀하는 방법에 대해 알아보겠습니다.


1. @EnableScheduling

해당 어노테이션을 통해 스케쥴링 기능을 사용하도록 설정합니다.

@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
public class PoppetApplication {
		public static void main(String[] args) {
		SpringApplication.run(PoppetApplication.class, args);
	}

2. @Scheduled

  • 스케쥴러를 사용하려는 클래스에 @Component annotation을 사용합니다.
  • 스케쥴러 기능을 수행할 함수에 @Scheduled annotation을 사용합니다.
    • 이 때 함수의 반환 타입은 void여야 하며, 매개 변수는 허용하지 않습니다.
@Slf4j
@Component
@RequiredArgsConstructor
public class EmailSendScheduler {
    private final EmailService emailService;

    // 매일 12시에 스케쥴러 수행
    @Scheduled(cron = "0 0 12 * * *")
    public void sendUnsentEmails() {
        emailService.sendEmail();
        log.info("[*] {} Email 전송 완료", LocalDateTime.now());
    }
}

2-1. fixedDelay

  • 메소드의 실행 종료 시점 기준 milliseconds 간격으로 수행합니다.
  • initDelay : 스케쥴러 초기화 후 정해진 시간만큼 대기한 후 fixedDelay에 명시된 밀리초 간격으로 수행합니다.
@Scheduled(fixedDelay = 1000, initialDelay = 5000)
    public void scheduleWithFixedDelay() throws InterruptedException {
        log.info("[*] Success to fixedDelay Scheduler : {}", LocalDateTime.now());
        Thread.sleep(1000L);
    }

1초 sleep한 후 1초 대기를 반복하며 함수를 수행하는 것을 확인할 수 있습니다.


2-2. fixedRate

  • 메소드의 실행 시작 시점 기준 milliseconds 간격으로 수행합니다.
  • 이전 작업이 끝날 때까지 대기하며, 병렬 작업에 유용합니다.
 @Scheduled(fixedRate = 1000)
    public void scheduleWithFixedRate() throws InterruptedException {
        log.info("[*] Success to fixedRate Scheduler : {}", LocalDateTime.now());
        Thread.sleep(1000L);
    }

fixedDelay와 다르게, sleep하는 1초와 관계없이 1초마다 함수를 수행하는 것을 확인할 수 있습니다.


2-3. cron

  • 표현식을 기반으로 작업을 예약할 수 있습니다.
@Scheduled(cron = "0/5 * * * * *")
    public void scheduleWithCron() throws InterruptedException {
        log.info("[*] Success to Cron Scheduler : {}", LocalDateTime.now());
    }

표현식을 통해 지정한대로 5초마다 함수를 수행하는 것을 확인할 수 있습니다.

표현식은 다음과 같은 기호로 나타낼 수 있으며, 스케쥴러 주기는 초 단위로 설정할 수 있습니다.

******
요일
0-590-590-231-311-120-7 (SUN-SAT)
* * * * * * // 매 초마다 실행

0 0 0/1 * * * // 매일 1시간 간격으로 실행

0 0 12 * * * // 매일 12시에 실행

0 0/10 12 * * * // 매일 12시부터 10분 간격으로 실행

0 0 12-14 * * * // 매일 12시, 13시, 14시에 실행

2-4. zone

  • cron으로 작업을 예약할 때 사용할 시간대를 설정합니다.
  • 따로 설정하지 않을 경우 Local Time Zone으로 지정됩니다.



3. Scheduler Thread Custom

위의 내용으로도 충분히 서비스 단에서 스케쥴러 기능을 구현해낼 수 있습니다.

그러나, 스케쥴러는 단일 쓰레드로 운영됩니다. 아래 테스트로 인해 두 개의 스케쥴러 함수는 scheduling-1 thread에 의해 호출되는 것을 알 수 있습니다.

@Scheduled(fixedDelay = 1000, initialDelay = 5000)
    public void scheduleWithFixedDelay() throws InterruptedException {
        Thread.sleep(1000L);
        log.info("[*] fixedDelay Scheduler's Thread Name : {}", Thread.currentThread().getName());
    }

    @Scheduled(cron = "0/5 * * * * *")
    public void scheduleWithCron() throws InterruptedException {
        log.info("[*] Cron Scheduler's Thread Name : {}", Thread.currentThread().getName());
    }

스케쥴러 작업이 많아질 경우를 대비하여 쓰레드 풀을 임의로 커스텀해보겠습니다!

3-1. YML File Custom

  • application.yml의 내용을 수정해 쓰레드풀의 크기를 설정하는 방법입니다.
  • 크기를 8로, 쓰레드 이름의 prefix를 custom-scheduler로 설정했습니다.
spring:
  task:
    scheduling:
      pool:
        size: 8
      thread-name-prefix: custom-scheduler

위의 설정에 따른 결과는 다음과 같습니다.
기존 scheduling-1 쓰레드로만 수행되던 작업들을 지정한 prefix를 이름으로 하는 쓰레드들이 나누어 수행하는 것을 확인할 수 있습니다.


3-2. Configuration Custom

YML 파일이 아닌 config 파일을 통해 스케쥴러를 커스텀해보겠습니다.
수행 결과는 3-1과 동일합니다.

@Configuration
public class SchedulerConfig {
    private final int POOL_SIZE = 8;

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("custom-scheduler");
        return threadPoolTaskScheduler;
    }
}

Spring Scheduler을 활용해 간단하게 스케쥴링 기능을 구현할 수 있습니다. 다음 포스트에서는 스케쥴링 주기를 동적으로 변경하는 기능에 대해 다루어보겠습니다.


Reference
https://velog.io/@developer_khj/Spring-Boot-Scheduler-Scheduled
https://www.baeldung.com/spring-scheduled-tasks
https://jeong-pro.tistory.com/186

profile
CS 마스터를 향해 ..

0개의 댓글