Compare commits
No commits in common. "481b14a98cf4e38cf351cdd13eb6dd97c1fff5cb" and "70c6bbb07d337d2d2a1c1d141ffed9c172bb794d" have entirely different histories.
481b14a98c
...
70c6bbb07d
@ -29,9 +29,7 @@ public class QuartzConfig {
|
||||
SchedulerFactoryBean factory = new SchedulerFactoryBean();
|
||||
factory.setJobFactory(springBeanJobFactory(applicationContext));
|
||||
factory.setOverwriteExistingJobs(true);
|
||||
// SchedulerInitializer에서 직접 start() 호출하므로 자동 시작 비활성화
|
||||
// 자동 시작 시 JDBC Store의 기존 trigger가 로드되어 중복 실행 발생 가능
|
||||
factory.setAutoStartup(false);
|
||||
factory.setAutoStartup(true);
|
||||
// DataSource는 Spring Boot가 자동 주입 (application.yml의 spring.datasource 사용)
|
||||
|
||||
return factory;
|
||||
|
||||
@ -10,7 +10,6 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 애플리케이션 시작 시 DB에 저장된 스케줄을 Quartz에 자동 로드
|
||||
@ -35,15 +34,11 @@ public class SchedulerInitializer {
|
||||
log.info("========================================");
|
||||
|
||||
try {
|
||||
// 기존 orphan trigger 전체 정리 (이전 실행에서 남은 잔여 trigger 제거)
|
||||
cleanupOrphanTriggers();
|
||||
|
||||
// DB에서 활성화된 스케줄 조회
|
||||
List<JobScheduleEntity> activeSchedules = scheduleRepository.findAllActive();
|
||||
|
||||
if (activeSchedules.isEmpty()) {
|
||||
log.info("활성화된 스케줄이 없습니다.");
|
||||
startSchedulerIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -72,7 +67,10 @@ public class SchedulerInitializer {
|
||||
log.info("========================================");
|
||||
|
||||
// Quartz 스케줄러 시작
|
||||
startSchedulerIfNeeded();
|
||||
if (!scheduler.isStarted()) {
|
||||
scheduler.start();
|
||||
log.info("Quartz 스케줄러 시작됨");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("스케줄러 초기화 중 에러 발생", e);
|
||||
@ -81,7 +79,6 @@ public class SchedulerInitializer {
|
||||
|
||||
/**
|
||||
* 개별 스케줄을 Quartz에 등록
|
||||
* Trigger를 먼저 명시적으로 제거한 후 Job을 삭제하여 orphan trigger 방지
|
||||
*
|
||||
* @param schedule JobScheduleEntity
|
||||
* @throws SchedulerException Quartz 스케줄러 예외
|
||||
@ -91,13 +88,7 @@ public class SchedulerInitializer {
|
||||
JobKey jobKey = new JobKey(jobName, "batch-jobs");
|
||||
TriggerKey triggerKey = new TriggerKey(jobName + "-trigger", "batch-triggers");
|
||||
|
||||
// 1. 기존 Trigger 명시적 제거 (orphan trigger 방지)
|
||||
if (scheduler.checkExists(triggerKey)) {
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
log.debug("기존 Quartz Trigger 제거: {}", triggerKey);
|
||||
}
|
||||
|
||||
// 2. 기존 Job 삭제 (연결된 trigger도 함께 삭제됨)
|
||||
// 기존 스케줄 확인 및 삭제
|
||||
if (scheduler.checkExists(jobKey)) {
|
||||
scheduler.deleteJob(jobKey);
|
||||
log.debug("기존 Quartz Job 삭제: {}", jobName);
|
||||
@ -127,47 +118,4 @@ public class SchedulerInitializer {
|
||||
log.debug(" → 다음 실행 예정: {}", trigger.getNextFireTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quartz 스케줄러가 아직 시작되지 않았으면 시작
|
||||
*/
|
||||
private void startSchedulerIfNeeded() throws SchedulerException {
|
||||
if (!scheduler.isStarted()) {
|
||||
scheduler.start();
|
||||
log.info("Quartz 스케줄러 시작됨");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 앱 시작 시 batch-triggers 그룹의 모든 기존 trigger와 batch-jobs 그룹의 모든 기존 job을 제거
|
||||
* JDBC Store에 잔존하는 orphan trigger로 인한 중복 실행 방지
|
||||
*/
|
||||
private void cleanupOrphanTriggers() throws SchedulerException {
|
||||
// batch-triggers 그룹의 모든 trigger 제거
|
||||
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(
|
||||
org.quartz.impl.matchers.GroupMatcher.triggerGroupEquals("batch-triggers"));
|
||||
if (!triggerKeys.isEmpty()) {
|
||||
log.info("기존 trigger {} 개 정리 시작 (batch-triggers 그룹)", triggerKeys.size());
|
||||
for (TriggerKey tk : triggerKeys) {
|
||||
scheduler.unscheduleJob(tk);
|
||||
log.debug(" Trigger 제거: {}", tk);
|
||||
}
|
||||
}
|
||||
|
||||
// batch-jobs 그룹의 모든 job 제거
|
||||
Set<JobKey> jobKeys = scheduler.getJobKeys(
|
||||
org.quartz.impl.matchers.GroupMatcher.jobGroupEquals("batch-jobs"));
|
||||
if (!jobKeys.isEmpty()) {
|
||||
log.info("기존 job {} 개 정리 시작 (batch-jobs 그룹)", jobKeys.size());
|
||||
for (JobKey jk : jobKeys) {
|
||||
scheduler.deleteJob(jk);
|
||||
log.debug(" Job 제거: {}", jk);
|
||||
}
|
||||
}
|
||||
|
||||
if (!triggerKeys.isEmpty() || !jobKeys.isEmpty()) {
|
||||
log.info("기존 스케줄 정리 완료: trigger {} 개, job {} 개 제거",
|
||||
triggerKeys.size(), jobKeys.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +253,6 @@ public class ScheduleService {
|
||||
|
||||
/**
|
||||
* Quartz에 Job 등록
|
||||
* Trigger → Job 순서로 명시적 제거 후 새로 등록하여 orphan trigger 방지
|
||||
*
|
||||
* @param entity JobScheduleEntity
|
||||
* @throws SchedulerException Quartz 스케줄러 예외
|
||||
@ -263,18 +262,6 @@ public class ScheduleService {
|
||||
JobKey jobKey = new JobKey(jobName, "batch-jobs");
|
||||
TriggerKey triggerKey = new TriggerKey(jobName + "-trigger", "batch-triggers");
|
||||
|
||||
// 1. 기존 Trigger 명시적 제거 (orphan trigger 방지)
|
||||
if (scheduler.checkExists(triggerKey)) {
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
log.debug("기존 Quartz Trigger 제거: {}", triggerKey);
|
||||
}
|
||||
|
||||
// 2. 기존 Job 삭제 (연결된 trigger도 함께 삭제됨)
|
||||
if (scheduler.checkExists(jobKey)) {
|
||||
scheduler.deleteJob(jobKey);
|
||||
log.debug("기존 Quartz Job 삭제: {}", jobName);
|
||||
}
|
||||
|
||||
// JobDetail 생성
|
||||
JobDetail jobDetail = JobBuilder.newJob(QuartzBatchJob.class)
|
||||
.withIdentity(jobKey)
|
||||
@ -290,9 +277,23 @@ public class ScheduleService {
|
||||
.forJob(jobKey)
|
||||
.build();
|
||||
|
||||
// Quartz에 스케줄 등록
|
||||
// 기존 Job 삭제 후 등록
|
||||
try {
|
||||
scheduler.deleteJob(jobKey);
|
||||
} catch (Exception e) {
|
||||
log.debug("기존 Job 삭제 시도: {}", jobName);
|
||||
}
|
||||
|
||||
// Job 등록
|
||||
try {
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
log.info("Quartz에 스케줄 등록 완료: {} (Cron: {})", jobName, entity.getCronExpression());
|
||||
} catch (ObjectAlreadyExistsException e) {
|
||||
log.warn("Job이 이미 존재함, 재시도: {}", jobName);
|
||||
scheduler.deleteJob(jobKey);
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
log.info("Quartz에 스케줄 재등록 완료: {} (Cron: {})", jobName, entity.getCronExpression());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user