Spring Boot에서 스케줄링
Cron은 정해진 시각에 작업을 반복 실행하기 위한 스케줄 표현 방식이다. 서버에서 매일 새벽 배치를 실행하거나 주기적으로 데이터를 수집할 때 사용한다. Spring Boot에서는 @Scheduled로 간단히 적용할 수 있다.
Cron 표현식
일반적인 Linux crontab은 5개 필드를 사용하지만, Spring의 @Scheduled(cron = ...)은 초를 포함한 6개 필드를 사용한다.
초 분 시 일 월 요일
0 0 3 * * *위 표현식은 매일 오전 3시에 실행된다는 뜻이다.
*: 모든 값
*/5: 5 단위 간격
1,3,5: 지정한 값
MON-FRI: 월요일부터 금요일
?: 일 또는 요일 필드에서 특정 값을 지정하지 않을 때 사용할 수 있는 표현
자주 사용하는 예시
| Cron 표현식 | 실행 시각 |
0 */5 * * * * | 5분마다 |
0 0 * * * * | 매시간 정각 |
0 0 3 * * * | 매일 오전 3시 |
0 0 9 * * MON-FRI | 평일 오전 9시 |
0 0 0 1 * * | 매월 1일 자정 |
Spring Boot 적용
스케줄링을 활성화한 뒤 @Scheduled 메서드를 작성하면 된다.
@Configuration
@EnableScheduling
public class SchedulingConfig {
}
@Component
public class BatchScheduler {
@Scheduled(cron = "0 0 3 * * *", zone = "Asia/Seoul")
public void runDailyBatch() {
// 배치 실행
}
}zone을 지정하면 서버의 기본 시간대에 의존하지 않고 원하는 시간대를 기준으로 실행할 수 있다. 매일 특정 시각에 실행하는 배치라면 이를 명시하는 편이 안전하다.
여러 서버의 중복 실행 방지: ShedLock
@Scheduled는 각 Spring Boot 인스턴스에서 독립적으로 실행된다. 예를 들어 Pod가 3개라면 같은 배치가 세 번 시작될 수 있다.
ShedLock은 PostgreSQL이나 Redis 같은 공통 저장소에 잠금을 기록해, 여러 인스턴스 중 하나만 같은 이름의 스케줄 작업을 실행하도록 돕는 라이브러리다. 다른 인스턴스는 잠금이 풀리기를 기다리지 않고 해당 실행을 건너뛴다.
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "30m")
public class SchedulingConfig {
}
@Component
public class BatchScheduler {
@Scheduled(cron = "0 0 3 * * *", zone = "Asia/Seoul")
@SchedulerLock(name = "dailyBatch",
lockAtMostFor = "30m",
lockAtLeastFor = "1m")
public void runDailyBatch() {
// 배치 실행
}
}예시는 기존 스케줄 메서드에 @SchedulerLock을 붙인 형태다. 실제 사용 시 ShedLock 라이브러리 의존성과 LockProvider 설정이 추가로 필요하다.
name: 인스턴스들이 공유하는 잠금 식별자
lockAtMostFor: 서버가 비정상 종료되더라도 잠금이 만료되는 최대 시간
lockAtLeastFor: 작업이 일찍 끝나도 잠금을 유지하는 최소 시간
주의할 점: 작업이 lockAtMostFor보다 오래 걸리면 잠금이 먼저 만료되어 중복 실행될 수 있다. ShedLock은 분산 스케줄러나 작업 큐가 아니며, 정확히 한 번 실행을 보장하지도 않는다. Cron은 언제 실행할지, ShedLock은 동시에 누가 실행할지를 제어하는 역할이다.
주의할 점
Cron은 정해진 실행 시각에 서버가 중단돼 있으면 작업을 자동으로 보충 실행하지 않는다. 시간대와 실행 주기 외에도 중복 실행, 작업 실패, 재시도를 별도로 고려해야 한다.