스프링 부트로 기능을 구현하다 보니 일정시간에 작업을 진행해야 하는 경우가 생긴다.
예를 들어 매일 12시에 맞춰 그날로부터 며칠이상 존재했던 데이터를 삭제하는 경우라던지, 새로운 데이터를 구해야 하는 것(전일 기준 인기 순위와 같은...)과 같은 작업을 진행해야 할 필요가 생긴다.
그래서 어떻게 하면 기능을 구현할 수 있을지 찾아본 결과 크게 두가지 방법으로 진행할 수 있는 것으로 확인했다.
바로 quartz와 spring scheduler이다.
quartz는 조금 설정방법이 어려운 대신 섬세하게 설정이 가능하며 스케줄러 간의 클러스팅이라던가 후처리기능이 더 뛰어나다.
이번에는 단순하게 일정 기간 이후에 데이터를 삭제하는 작업을 진행하게 되어 간단하게 spring scheduler를 사용해보려고 한다.
spring scheduler
스프링 부트에 기본적으로 포함되어 있는 라이브러리로 간편하게 특정시간에 특정작업을 진행해야 하는 경우에 사용한다.
대부분 Batch와 함께 사용하는 경우가 많지만 대규모 병렬처리를 하지 않는 경우 꼭 Batch를 사용하지 않아도 된다.
사용방법
Scheduler 활성화
스프링 스케줄러는 스프링부트를 사용할 경우에는 이미 의존성이 포함되어 있기에 따로 추가해주지 않아도 된다.
단지 Application 클래스 (스프링 실행 클래스)에 @EnableScheduling
만 추가 해주면 된다.
정말 간편 그자체다!!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 추가된 어노테이션
public class SchedulerTestApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerTestApplication.class, args);
}
}
Scheduler 작업 만들기
작업할 메서드를 만들고 메서드에 @Scheduled()
를 달아주면 된다.
이때 동작시킬 시간을 설정해 주면 된다. 아래의 예시는 5초마다 현재 시간을 출력하는 메서드이다.
fixedDelay 간격은 메서드 호출이 완료되는 시점부터 기록된다. 즉 5초의 간격을 두고 2초가 걸리는 작업이면 아래와 같이 한 사이클에 총 7초가 소요되게 된다.
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@Slf4j
public class ScheduledTasks {
@Scheduled(fixedDelay = 5000)
public void reportCurrentTime(){
log.info("현재 시간은 {} 입니다.", LocalDateTime.now());
}
}
@Scheduled()
의 fixedRate의 단위는 밀리초이지만 timeUnit 속성을 통해 단위를 변경할 수 있다
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)
고정 속도로 실행하기 (fixedRate)
또한 만약 고정된 속도로 실행하고 싶다면 fixedDelay속성이 아닌 fixedRate로 변경해 주면 된다. 그러면 아래와 같이 실행한다.
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
이 속성을 사용하는 경우 처음에 대기할 시간도 정할 수 있다.
@Scheduled(initialDelay = 1, fixedRate = 5, timeUnit = TimeUnit.SECONDS)
Cron 표현식
Cron 표현식을 사용해서 실행시간을 정해줄 수 있다.
@Scheduled(cron = "* * * * * *")
이렇게 시간을 지정해 주면 된다.
그리고 특수문자를 사용할 수 있는데
*
은 전체 (first-last)를 의미한다. day of month(일)과 day of th week(요일)에는 ?가 같은 의미로 사용 가능하다,
는 항목을 구분할 때 사용!-
은 범위를 지정할 때 쓴다 " 0 0 8-10 * * * "으로 사용하면 매일 8시 0분 0초, 9시 0분 0초, 10시 0분 0초에 실행한다는 의미/
은 범위 혹은 숫자 값 뒤에 쓰는데 간격을 지정할 수 있다. 예를 들어 " 0 30/5 * * * * "은 매 시간 30분부터 5분마다 실행하라는 의미L
은 날짜 및 요일 필드에 숫자 대신 사용하는데 마지막을 의미한다. 예를 들어 " 0 0 0 L * * "은 매월 마지막 날을 의미한다. 또한 " 0 0 0 L-3 * * "은 그 달의 3일부터 마지막 날까지라는 의미다.- 일 필드에 숫자 뒤에
W
가 붙는다면 (nW 형식) 그날과 가장 가까운 평일이라는 뜻이다. 예를 들어 " 0 0 0 1W * * "은 매월 첫째 주 평일을 의미한다. LW로 작성 시 마지막 평일날이다
스케줄러에서는 간편하게 줄여서 가독성을 높일 수 있도록 자주 사용되는 주기를 어노테이션으로 만들어 두었다.
사용 방법은
@Scheduled(cron = "@hourly")
- @yearly (또는 @annually)
- 1년에 한 번 ( 0 0 0 1 1 * )과 같음
- @monthly
- 한 달에 한번 ( 0 0 0 1 * * )
- @weekly
- 일주일에 한 번 ( 0 0 0 * * 0 )
- @daily (또는 @midnight)
- 하루에 한 번 (0 0 0 * * * )
- @hourly
- 한 시간에 한 번 ( 0 0 * * * * )
이렇게 간단하게 일정작업을 적용할 수 있는 스케줄러에 대해서 알아보았다. 만약 작업이 방대해서 대규모 병렬이 필요하다면 Batch를 함께 사용하는 것이 좋고, 그게 아니더라도 비동기로 처리해야 한다면 @Async를 활용해 처리하는 것도 방법이 될 수 있을 것 같다.
'Library & Framework > Spring' 카테고리의 다른 글
AOP에 대해 알아보자 (0) | 2023.08.04 |
---|---|
필터(filter), 인터셉터(interceptor), AOP(Aspect-Oriented Programming) 살펴보기 (0) | 2023.07.22 |
[Spring boot] war로 배포하기, SpringBootServletInitalizer (0) | 2023.07.22 |
[Spring boot] 설정 정보(application.yml / properties) 분리시키기 - spring profiles (0) | 2023.06.12 |
[Spring boot] 설정 정보 외부에서 관리하기 2 - submodule (0) | 2023.03.21 |