QRTZ_ 테이블로 인해 Job에 대한 정보
Trigger에 대한 정보도 모두 확인이 가능하다
그렇다면 코드로 JobDetail, Trigger를 등록하지 않고
Admin Page를 만들어서 데이터를 관리해봐야겠다
스케줄에 필요한 정보는 Job, Trigger가 있습니다.
Job과 Trigger를 등록 및 수정하기 위해, 기존 방식을 확인해보자
아래와 같이 설정하면 구동 시 QRTZ_
테이블이 삭제되고 새롭게 생성된다
그와 동시에 Job, Trigger 정보도 들어가게되는데
spring:
quartz:
jdbc:
initialize-schema: "always"
@Bean
public JobDetail jobDetail() {
//Set Job data map
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("jobName", "testJob");
jobDataMap.put("jobLauncher", jobLauncher);
jobDataMap.put("jobLocator", jobLocator);
return JobBuilder.newJob(QuartzJob.class)
.withIdentity("testJob", null)
.setJobData(jobDataMap)
.storeDurably()
.build();
}
그리고 아래 테이블을 조회해보면은
SELECT * FROM QRTZ_JOB_DETAILS qjd ;
Data가 들어간걸 확인할 수 있다.
여기서 특이한 점은 JOB_DATA의 값이 이상하는 점
Trigger도 Job과 동일하게 확인을 해보면은
@Bean
public Trigger trigger() {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(60)
.repeatForever();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
.cronSchedule("0 * * * * ?");
return TriggerBuilder
.newTrigger()
.forJob(jobOneDetail().getKey())
.withIdentity("trigger", null)
.withSchedule(scheduleBuilder)
.build();
}
SELECT * FROM QRTZ_TRIGGERS qt ;
QRTZ_TRIGGERS
테이블은 Trigger Type과 상관없이 필수로 데이터가 있어야한다.
SELECT * FROM QRTZ_CRON_TRIGGERS qct ;
QRTZ_CRON_TRIGGERS
테이블은 QRTZ_TRIGGERS-TRIGGER_TYPE
이 CRON인 경우 정보가 들어오게 된다
SELECT * FROM QRTZ_SIMPLE_TRIGGERS qst ;
QRTZ_CRON_TRIGGERS
테이블은 QRTZ_TRIGGERS-TRIGGER_TYPE
이 SIMPLE인 경우 정보가 들어오게 된다
QRTZ_TRIGGERS
테이블을 보면 다음 실행 시간, 이전 실행 시간, 시작 시간 컬럼이 있으며
기입된 시간 역시 일반적인 시간정보가 아니였다
다른 컬럼에 대해서는 자신이 세팅한 값을 기입하면 되고 JOB_DATA
인 경우에는
값을 그대로 넣을 수 없었다.
컬럼 데이터 타입이 BLOB
으로 되어있었기 때문에, 화면에서 문자로 기입 받은 내용을 변환하는 작업이 필요했다.
JOB_DATA는 전 Json 형식의 String으로 입력받았고,
String
-> Object
-> 직렬화
-> byte[]
String jobData = "{"jobName":"testJob"}";
byte[] blobJobData = null;
JobDataMap jobDataMap = new JobDataMap();
ObjectMapper objectMapper = new ObjectMapper();
jobDataMap = objectMapper.readValue(jobData, jobDataMap.getClass());
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
objectOutputStream.writeObject(jobDataMap);
blobJobData = byteArrayOutputStream.toByteArray();
}
}
위 과정을 거쳐 DB에 기입했고, 반대로 조회인 경우도 위 순서의 반대로 가져왔다.
Trigger인 경우에는 _TIME
컬럼을 제외한 나머지 값은 그대로 기입하면 된다.
_TIME
컬럼인 경우 NUMBER(13,0)
데이터 타입을 사용하고 있었다.
해당 데이터 타입으로 변환을 할려면 Epoch
로 변환을 해야한다.
String
-> Date
-> Long
CronExpression
을 기입받아 CronSequenceGenerator
를 사용했고,
Simple
인 경우에는 MILLISECOND
입력받아
Date
값으로 변환했다.
LocalDateTime.parse(dataFormat.format(date), DateTimeFormatter.ofPattern(dateformat))
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
위 처럼 타입 변환 후 기입 처리, 반대로 read
할때는 역순으로 진행
Trigger
정보를 넣을 때
Cron
이면 QRTZ_TRIGGERS
-> QRTZ_CRON_TRIGGERS
순서로 INSERT 처리
반대로 삭제를 할때는 역순으로 삭제처리를 해야한다.
그리고 JOB_NAME
도 QRTZ_JOB_DETAILS
테이블에 있는 JOB_NAME
을 기입해야한다
QRTZ_JOB_DETAILS
테이블 JOB_DATA
를 보면 {"jobName":"testJob"}
들어가있다.
ADMIN PAGE에서 Job을 등록할때도 동일하게 넣어줘야 실행이된다.
이제 코드에서 JobBuilder, TriggerBuilder 를 사용하지 않고, 등록이 가능하다.
화면에서 Job, Trigger에 대한 정보를 한 눈에 확인할 수 있으니 편하다
필요시 Trigger를 등록하여 일회성으로 실행할 수 있다.
#[Quartz] Spring Batch Re-Schedule When Fail (JDBC) 게시물에서 에러로 인한 Trigger가 등록이 된경우에도 확인이 가능하니, 편리하다
JOB_DATA를 수정해 Job 실행 시 분기처리가 편리했다.