들어가기 앞서
현재 진행 중인 팀 프로젝트에서는 검색어를 입력할 시 해당 검색어를 저장해 주고 Keyword Entity에 저장된 검색어들을 Count하여 1위부터 10위까지 인기 순위를 조회해 볼 수 있는 API가 있습니다.
여기서 발생할 수 있는 문제점은 검색어 모두 저장해 주다 보면, 너무 많은 양의 검색어가 데이터베이스에 쌓인다는 것인데요,
3일이라는 기간을 정해 놓고, 저장된 지 3일이 지난 검색어들은 매일 자정에 자동으로 삭제될 수 있도록 설정하기 위해 Scheduler 기능을 활용하게 되었습니다.
1. Scheduler 구현하기
(1-1) Scheduler 활성화하기
Scheduler는 기본적으로 Spring Boot에 포함되어 있어, Gradle에 의존성 설정 추가할 필요는 없고, Application Class에 @EnableScheduling Annotation을 추가하여 Scheduler 기능을 활성화시켜주어야 합니다.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableScheduling
@SpringBootApplication
@EnableScheduling
class MovieReviewApplication
fun main(args: Array<String>) {
runApplication<MovieReviewApplication>(*args)
}
(1-2) Scheduler 사용하기
이제 스케쥴러를 구현할 Method를 작성해 줘야 하는데, 유의할 점은 해당 Scheduler가 사용되어야 하는 곳은 SpringBean에 등록되어 있어야 합니다! (저는 이전부터 @Service Annotation을 설정해 놓았기 때문에 별도 추가 설정을 필요하지 않았으며, 일반적으로 @Component Annotation을 사용 사용할 클래스를 Spring Bean으로 등록합니다!)
@Service
class KeywordService(private val keywordRepository: KeywordRepository) {
@Scheduled(cron = "0 0 0 * * ?")
fun deleteOldKeywords() {
val expiryDate = LocalDateTime.now().minusDays(3)
keywordRepository.deleteKeywords(expiryDate)
}
}
사용해야 할 Method에 @Scheduled Annotation을 붙이고, Method를 작성하면 되는데 코드를 자세히 살펴보기 전 @Scheduled Annotation의 속성을 살펴보려 합니다.
(1-3) Scheduler 속성 살펴보기
- fixedRate : 작업 수행 시간과 상관없이 일정 주기마다 메소드를 호출합니다.
- fixedDelay : (작업 수행 시간을 포함) 작업을 마친 후부터 주기 타이머가 돌아 메소드를 호출합니다.
- initialDelay: 스케줄러에서 메소드가 등록되자마자 수행하는 것이 아닌 초기 지연시간을 설정하고, 이후 일정 주기마다 메소드를 호출할 수 있습니다.
- cron: Cron 표현식을 사용하여 작업을 일정 주기 별 작업을 예약할 수 있습니다.
(1-4) Scheduler 사용 Method 뜯어보기
먼저 cron 표현식을 사용했기에, 해당 표현식이 뭔지 알아보려 합니다. cron 표현식은 시간을 기반으로 작업을 예약하는 방법으로 다음과 같은 형식으로 구성됩니다.
- Seconds: 0-59
- Minutes: 0-59
- Hours: 0-23
- Day-of-month: 1-31
- Month: 1-12 또는 JAN-DEC
- Day-of-week: 0-7 (0 또는 7은 일요일) 또는 SUN-SAT
그래서 위에서 작성한 코드 "@Scheduled(cron = "0 0 0 * * ?")"는 매일 자정 자동 삭제 함수가 실행되며,
"*"는 모든 값을 의미하고(즉 모든 날짜, 모든 달에 해당 메소드를 실행합니다), "?"는 특정 값을 지정하지 않는 다는 것을 의미합니다!(Day-of-month와 Day-of-week 필드에서 사용할 수 있습니다)
"keywordRepository.deleteKeywords()" 코드를 살펴보면 아래와 같습니다.
fun deleteKeywords(expiryDate: LocalDateTime) {
val keyword = QKeyword.keyword
queryFactory.delete(keyword)
.where(keyword.createdAt.before(expiryDate))
.execute()
}
QueryDSL을 통해 유효기간보다 이전에 등록된 데이터들은 삭제되도록 설정해주고,
Service Layer에서 ExpiaryDate를 해당 메서드가 실행되는 시점의 3일 전으로 설정해주어 최종적으로 데이터의 유통기한을 3일로 설정해주었습니다.
스케쥴러 사용 시, 참고한 블로그 링크를 하단에 첨부해놓습니다! 해당 글을 포스팅할 때도 많이 참고한 글이어서, 스케쥴러 활용 시 참고해보면 좋을 것 같습니다.