fix(스케줄러): Quartz JDBC Store 미적용 수정 — RAMJobStore에서 JDBC Store로 전환 (#12) #52
@ -41,6 +41,7 @@
|
|||||||
- 재수집 관리 및 이력 추가 (#4)
|
- 재수집 관리 및 이력 추가 (#4)
|
||||||
- 재수집 중복 실행 문제 해결 (#9)
|
- 재수집 중복 실행 문제 해결 (#9)
|
||||||
- Quartz orphan trigger 제거 (#12)
|
- Quartz orphan trigger 제거 (#12)
|
||||||
|
- Quartz JDBC Store 미적용 수정 — RAMJobStore에서 JDBC Store로 전환 (#12)
|
||||||
- 마지막 성공 일시 세팅 방법 수정 (#15)
|
- 마지막 성공 일시 세팅 방법 수정 (#15)
|
||||||
- 테스트용 IMO 목록 건수 제한 제거 (#32)
|
- 테스트용 IMO 목록 건수 제한 제거 (#32)
|
||||||
- 타임라인 상세 화면 이동 오류 수정 및 실행 중 작업 상세 버튼 추가 (#34)
|
- 타임라인 상세 화면 이동 오류 수정 및 실행 중 작업 상세 버튼 추가 (#34)
|
||||||
|
|||||||
@ -11,28 +11,43 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
|||||||
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quartz 설정
|
* Quartz 설정
|
||||||
* Spring Boot Auto-configuration을 사용하면서 JobFactory만 커스터마이징
|
* 커스텀 SchedulerFactoryBean을 정의하면 Spring Boot auto-configuration이 비활성화되므로
|
||||||
|
* DataSource와 QuartzProperties를 명시적으로 주입해야 한다.
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class QuartzConfig {
|
public class QuartzConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quartz Scheduler Factory Bean 설정
|
* Quartz Scheduler Factory Bean 설정
|
||||||
* Spring Boot Auto-configuration이 DataSource를 자동 주입하므로
|
* DataSource, QuartzProperties를 명시적으로 주입하여 JDBC Store 사용 보장
|
||||||
* JobFactory만 커스터마이징
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public SchedulerFactoryBean schedulerFactoryBean(ApplicationContext applicationContext) {
|
public SchedulerFactoryBean schedulerFactoryBean(
|
||||||
|
ApplicationContext applicationContext,
|
||||||
|
DataSource dataSource,
|
||||||
|
QuartzProperties quartzProperties) {
|
||||||
|
|
||||||
SchedulerFactoryBean factory = new SchedulerFactoryBean();
|
SchedulerFactoryBean factory = new SchedulerFactoryBean();
|
||||||
factory.setJobFactory(springBeanJobFactory(applicationContext));
|
factory.setJobFactory(springBeanJobFactory(applicationContext));
|
||||||
|
factory.setDataSource(dataSource);
|
||||||
factory.setOverwriteExistingJobs(true);
|
factory.setOverwriteExistingJobs(true);
|
||||||
// SchedulerInitializer에서 직접 start() 호출하므로 자동 시작 비활성화
|
// SchedulerInitializer에서 직접 start() 호출하므로 자동 시작 비활성화
|
||||||
// 자동 시작 시 JDBC Store의 기존 trigger가 로드되어 중복 실행 발생 가능
|
// 자동 시작 시 JDBC Store의 기존 trigger가 로드되어 중복 실행 발생 가능
|
||||||
factory.setAutoStartup(false);
|
factory.setAutoStartup(false);
|
||||||
// DataSource는 Spring Boot가 자동 주입 (application.yml의 spring.datasource 사용)
|
|
||||||
|
// application.yml의 spring.quartz.properties 적용
|
||||||
|
// jobStore.class와 driverDelegateClass는 setDataSource()가 내부적으로 설정하므로 제외
|
||||||
|
Properties properties = new Properties();
|
||||||
|
quartzProperties.getProperties().forEach((key, value) -> {
|
||||||
|
if (!key.contains("jobStore.class") && !key.contains("driverDelegateClass")) {
|
||||||
|
properties.put(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
factory.setQuartzProperties(properties);
|
||||||
|
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ spring:
|
|||||||
quartz:
|
quartz:
|
||||||
job-store-type: jdbc # JDBC store for schedule persistence
|
job-store-type: jdbc # JDBC store for schedule persistence
|
||||||
jdbc:
|
jdbc:
|
||||||
initialize-schema: always # Create Quartz tables if not exist
|
initialize-schema: never # Quartz tables manually created in std_snp_data schema
|
||||||
properties:
|
properties:
|
||||||
org.quartz.scheduler.instanceName: SNPBatchScheduler
|
org.quartz.scheduler.instanceName: SNPBatchScheduler
|
||||||
org.quartz.scheduler.instanceId: AUTO
|
org.quartz.scheduler.instanceId: AUTO
|
||||||
|
|||||||
@ -42,7 +42,7 @@ spring:
|
|||||||
quartz:
|
quartz:
|
||||||
job-store-type: jdbc # JDBC store for schedule persistence
|
job-store-type: jdbc # JDBC store for schedule persistence
|
||||||
jdbc:
|
jdbc:
|
||||||
initialize-schema: always # Create Quartz tables if not exist
|
initialize-schema: never # Quartz tables manually created in std_snp_data schema
|
||||||
properties:
|
properties:
|
||||||
org.quartz.scheduler.instanceName: SNPBatchScheduler
|
org.quartz.scheduler.instanceName: SNPBatchScheduler
|
||||||
org.quartz.scheduler.instanceId: AUTO
|
org.quartz.scheduler.instanceId: AUTO
|
||||||
|
|||||||
187
src/main/resources/sql/quartz_tables_postgres.sql
Normal file
187
src/main/resources/sql/quartz_tables_postgres.sql
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
-- Quartz Scheduler JDBC Store DDL for PostgreSQL
|
||||||
|
-- Schema: std_snp_data
|
||||||
|
-- tablePrefix 설정: std_snp_data.QRTZ_
|
||||||
|
--
|
||||||
|
-- 사용법: psql -d <database> -f quartz_tables_postgres.sql
|
||||||
|
|
||||||
|
SET search_path TO std_snp_data;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_LOCKS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
|
||||||
|
DROP TABLE IF EXISTS QRTZ_CALENDARS;
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_JOB_DETAILS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR(250) NULL,
|
||||||
|
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
|
||||||
|
IS_DURABLE BOOL NOT NULL,
|
||||||
|
IS_NONCONCURRENT BOOL NOT NULL,
|
||||||
|
IS_UPDATE_DATA BOOL NOT NULL,
|
||||||
|
REQUESTS_RECOVERY BOOL NOT NULL,
|
||||||
|
JOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NOT NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
DESCRIPTION VARCHAR(250) NULL,
|
||||||
|
NEXT_FIRE_TIME BIGINT NULL,
|
||||||
|
PREV_FIRE_TIME BIGINT NULL,
|
||||||
|
PRIORITY INTEGER NULL,
|
||||||
|
TRIGGER_STATE VARCHAR(16) NOT NULL,
|
||||||
|
TRIGGER_TYPE VARCHAR(8) NOT NULL,
|
||||||
|
START_TIME BIGINT NOT NULL,
|
||||||
|
END_TIME BIGINT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR(200) NULL,
|
||||||
|
MISFIRE_INSTR SMALLINT NULL,
|
||||||
|
JOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
REPEAT_COUNT BIGINT NOT NULL,
|
||||||
|
REPEAT_INTERVAL BIGINT NOT NULL,
|
||||||
|
TIMES_TRIGGERED BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_CRON_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
CRON_EXPRESSION VARCHAR(120) NOT NULL,
|
||||||
|
TIME_ZONE_ID VARCHAR(80),
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
STR_PROP_1 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_2 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_3 VARCHAR(512) NULL,
|
||||||
|
INT_PROP_1 INT NULL,
|
||||||
|
INT_PROP_2 INT NULL,
|
||||||
|
LONG_PROP_1 BIGINT NULL,
|
||||||
|
LONG_PROP_2 BIGINT NULL,
|
||||||
|
DEC_PROP_1 NUMERIC(13, 4) NULL,
|
||||||
|
DEC_PROP_2 NUMERIC(13, 4) NULL,
|
||||||
|
BOOL_PROP_1 BOOL NULL,
|
||||||
|
BOOL_PROP_2 BOOL NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_BLOB_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
BLOB_DATA BYTEA NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||||
|
FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_CALENDARS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR(200) NOT NULL,
|
||||||
|
CALENDAR BYTEA NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_FIRED_TRIGGERS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
ENTRY_ID VARCHAR(95) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||||
|
FIRED_TIME BIGINT NOT NULL,
|
||||||
|
SCHED_TIME BIGINT NOT NULL,
|
||||||
|
PRIORITY INTEGER NOT NULL,
|
||||||
|
STATE VARCHAR(16) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR(200) NULL,
|
||||||
|
JOB_GROUP VARCHAR(200) NULL,
|
||||||
|
IS_NONCONCURRENT BOOL NULL,
|
||||||
|
REQUESTS_RECOVERY BOOL NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, ENTRY_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SCHEDULER_STATE
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||||
|
LAST_CHECKIN_TIME BIGINT NOT NULL,
|
||||||
|
CHECKIN_INTERVAL BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_LOCKS
|
||||||
|
(
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
LOCK_NAME VARCHAR(40) NOT NULL,
|
||||||
|
PRIMARY KEY (SCHED_NAME, LOCK_NAME)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Indexes
|
||||||
|
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
|
||||||
|
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
|
||||||
|
|
||||||
|
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
|
||||||
|
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||||
|
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
|
||||||
|
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||||
불러오는 중...
Reference in New Issue
Block a user