122 lines
4.3 KiB
Java
122 lines
4.3 KiB
Java
package com.snp.batch.scheduler;
|
|
|
|
import com.snp.batch.global.model.JobScheduleEntity;
|
|
import com.snp.batch.global.repository.JobScheduleRepository;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.quartz.*;
|
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|
import org.springframework.context.event.EventListener;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import java.util.List;
|
|
|
|
/**
|
|
* 애플리케이션 시작 시 DB에 저장된 스케줄을 Quartz에 자동 로드
|
|
* ApplicationReadyEvent를 수신하여 모든 빈 초기화 후 실행
|
|
*/
|
|
@Slf4j
|
|
@Component
|
|
@RequiredArgsConstructor
|
|
public class SchedulerInitializer {
|
|
|
|
private final JobScheduleRepository scheduleRepository;
|
|
private final Scheduler scheduler;
|
|
|
|
/**
|
|
* 애플리케이션 준비 완료 시 호출
|
|
* DB의 활성화된 스케줄을 Quartz에 로드
|
|
*/
|
|
@EventListener(ApplicationReadyEvent.class)
|
|
public void initializeSchedules() {
|
|
log.info("========================================");
|
|
log.info("스케줄러 초기화 시작");
|
|
log.info("========================================");
|
|
|
|
try {
|
|
// DB에서 활성화된 스케줄 조회
|
|
List<JobScheduleEntity> activeSchedules = scheduleRepository.findAllActive();
|
|
|
|
if (activeSchedules.isEmpty()) {
|
|
log.info("활성화된 스케줄이 없습니다.");
|
|
return;
|
|
}
|
|
|
|
log.info("총 {}개의 활성 스케줄을 로드합니다.", activeSchedules.size());
|
|
|
|
int successCount = 0;
|
|
int failCount = 0;
|
|
|
|
// 각 스케줄을 Quartz에 등록
|
|
for (JobScheduleEntity schedule : activeSchedules) {
|
|
try {
|
|
registerSchedule(schedule);
|
|
successCount++;
|
|
log.info("✓ 스케줄 로드 성공: {} (Cron: {})",
|
|
schedule.getJobName(), schedule.getCronExpression());
|
|
|
|
} catch (Exception e) {
|
|
failCount++;
|
|
log.error("✗ 스케줄 로드 실패: {}", schedule.getJobName(), e);
|
|
}
|
|
}
|
|
|
|
log.info("========================================");
|
|
log.info("스케줄러 초기화 완료");
|
|
log.info("성공: {}개, 실패: {}개", successCount, failCount);
|
|
log.info("========================================");
|
|
|
|
// Quartz 스케줄러 시작
|
|
if (!scheduler.isStarted()) {
|
|
scheduler.start();
|
|
log.info("Quartz 스케줄러 시작됨");
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("스케줄러 초기화 중 에러 발생", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 개별 스케줄을 Quartz에 등록
|
|
*
|
|
* @param schedule JobScheduleEntity
|
|
* @throws SchedulerException Quartz 스케줄러 예외
|
|
*/
|
|
private void registerSchedule(JobScheduleEntity schedule) throws SchedulerException {
|
|
String jobName = schedule.getJobName();
|
|
JobKey jobKey = new JobKey(jobName, "batch-jobs");
|
|
TriggerKey triggerKey = new TriggerKey(jobName + "-trigger", "batch-triggers");
|
|
|
|
// 기존 스케줄 확인 및 삭제
|
|
if (scheduler.checkExists(jobKey)) {
|
|
scheduler.deleteJob(jobKey);
|
|
log.debug("기존 Quartz Job 삭제: {}", jobName);
|
|
}
|
|
|
|
// JobDetail 생성
|
|
JobDetail jobDetail = JobBuilder.newJob(QuartzBatchJob.class)
|
|
.withIdentity(jobKey)
|
|
.usingJobData("jobName", jobName)
|
|
.withDescription(schedule.getDescription())
|
|
.storeDurably(true)
|
|
.build();
|
|
|
|
// CronTrigger 생성
|
|
CronTrigger trigger = TriggerBuilder.newTrigger()
|
|
.withIdentity(triggerKey)
|
|
.withSchedule(CronScheduleBuilder.cronSchedule(schedule.getCronExpression())
|
|
.withMisfireHandlingInstructionDoNothing())
|
|
.forJob(jobKey)
|
|
.build();
|
|
|
|
// Quartz에 스케줄 등록
|
|
scheduler.scheduleJob(jobDetail, trigger);
|
|
|
|
// 다음 실행 시간 로깅
|
|
if (trigger.getNextFireTime() != null) {
|
|
log.debug(" → 다음 실행 예정: {}", trigger.getNextFireTime());
|
|
}
|
|
}
|
|
}
|