@Scheduled가 동작하지 않는 이유와 설정 조건
Spring의 @Scheduled
는 단순히 어노테이션을 붙이는 것만으로는 동작하지 않습니다. 다음과 같은 조건이 반드시 충족되어야 합니다.
✅ 필수 설정
@EnableScheduling
어노테이션 선언 필수- Bean으로 등록된 클래스에
@Scheduled
가 있어야 함 - Spring 컨텍스트가 살아 있어야 함 (즉, 애플리케이션이 실행 중이고 종료되지 않아야 함)
spring.batch.job.enabled=false
설정 (Spring Boot가 Job을 자동 실행하지 않도록 설정)- 메서드는 파라미터가 없어야 함 –
public void run()
형태여야 함
💥 예외 사례
아래와 같이 파라미터가 있는 메서드는 @Scheduled
에서 예외가 발생합니다:
@Scheduled(cron = "0 0 * * * ?")
public void runSampleJob(Job job) { // ❌ 오류 발생
✅ 올바른 예시
@Component
@EnableScheduling
public class SampleScheduler {
@Scheduled(cron = "0 0 * * * ?")
public void runSampleJob() {
// your logic
}
}
cron 표현식 정리
표현식 | 설명 |
---|---|
*/2 * * * * ? | 매 2초마다 실행 (6자리: 초 분 시 일 월 요일) |
0 0/2 * * * ? | ✅ 매 2분마다 1회 실행 |
0 0 1 * * ? | 매일 새벽 1시 실행 |
0 0 0 * * ? | 매일 자정 실행 |
@Scheduled가 루프처럼 반복 실행되는 이유
❗ 잘못된 cron 사용
*/2 * * * * ?
는 매 2초마다 실행을 의미합니다. “2분마다”로 잘못 이해하면 루프처럼 실행되는 문제가 발생합니다.
❗ JobParameters 중복
Spring Batch는 동일한 Job 이름과 동일한 JobParameters로는 중복 실행을 허용하지 않습니다. 동일 파라미터로 실행할 경우 예외가 발생하고, 이를 스케줄러가 계속 재시도하게 되면 루프처럼 보일 수 있습니다.
해결 방법
1. JobParameters에 timestamp 추가
JobParametersBuilder builder = new JobParametersBuilder();
builder.addString("key", "value");
builder.addLong("timestamp", System.currentTimeMillis());
JobParameters parameters = builder.toJobParameters();
2. 실행 중 Job 중복 방지
boolean isRunning = jobExplorer.findRunningJobExecutions(job.getName())
.stream()
.anyMatch(JobExecution::isRunning);
if (isRunning) {
log.warn("Job is already running. Skipping this schedule.");
return;
}
Sample 통합 코드 예시
@Component
@EnableScheduling
@RequiredArgsConstructor
public class SampleJobRunner {
private final ApplicationContext applicationContext;
private final JobLauncher jobLauncher;
private final JobExplorer jobExplorer;
private final ApplicationArguments applicationArguments;
@Scheduled(cron = "0 0/2 * * * ?") // 매 2분마다
public void runSampleJob() {
try {
Job sample = applicationContext.getBean("sample", Job.class);
boolean isRunning = jobExplorer.findRunningJobExecutions(sample.getName())
.stream()
.anyMatch(JobExecution::isRunning);
if (isRunning) {
log.warn("Job is already running. Skipping this execution.");
return;
}
JobParameters jobParameter = JobParametersUtils.convertArgsToBuilder(applicationArguments)
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(sample, jobParameter);
} catch (Exception e) {
log.error("스케쥴링 오류 발생", e);
}
}
}
결론
Spring의 @Scheduled
기능은 간단해 보이지만, cron 표현식의 정확한 해석, Spring Batch와의 연동에서 발생할 수 있는 JobParameters 중복 문제, 그리고 Job 중복 실행 방지 전략까지 실무에서는 반드시 종합적으로 고려되어야 합니다.
이 글에서는 @Scheduled를 사용할 때 반드시 필요한 설정부터 반복 실행 문제 해결, Job 실행 안정성 확보를 위한 팁까지 모두 정리했습니다. 반복 실행 이슈나 실행 안 되는 문제를 겪고 있다면 이 가이드를 바탕으로 점검해 보시기 바랍니다.