Framework/Spring-Quartz
(4) Spring Quartz Sample
by 조훙
2022. 11. 24.
Quartz Sample
build.gradle 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-quartz'
Quartz 관련 설정
- spring.quartz.properties 하위 속성은 Quartz 관련 Properties 속성 관련 정보 설정 가능
- JobStore 속성은 두가지 설정 가능
- RAMJobStore : 인메모리 기반의 Job Store로 휘발성
- JDBCJobStore : DB 기반의 Job Store로 비휘발성
- JDBC 연결을 통해 JobStore를 DB로 지정 가능
spring:
quartz:
wait-for-jobs-to-complete-on-shutdown: true #종료 시 실행 중인 작업이 완료 때까지 대기
job-store-type: memory #Job Store Type (memory / jdbc)
properties:
org:
quartz:
scheduler:
skipUpdateCheck: true
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 5
jobStore:
class: org.quartz.simpl.RAMJobStore
plugin:
shutdownhook: #로깅 시스템이 초기화 되면 종료 후크 등록
class: org.quartz.plugins.management.ShutdownHookPlugin
cleanShutdown: true\\
Quartz Sample Code
- Quartz를 이용해서 가장 간단하게 사용 할 수 있는 방법은 QuartzJobBean 을 상속받아 구현 하는 것이다.
package com.navercorp.quartz_setting.quartz;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.quartz.QuartzJobBean;
import lombok.extern.slf4j.Slf4j;
/**
* SampleJob 코드
*
*/
@Slf4j
public class SampleJob extends QuartzJobBean {
private int MAX_SLEEP_IN_SECONDS = 5;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String Dev = jobDataMap.getString("Dev");
String Company = jobDataMap.getString("Company");
JobKey jobKey = context.getJobDetail().getKey();
log.info("===========================================");
log.info("Develope by {} from {}", Dev, Company);
log.info("CronJob started :: sleep : {} jobKey : {}", MAX_SLEEP_IN_SECONDS, jobKey);
IntStream.range(0,4).forEach(
i -> {
log.info("CronJob Counting - {}", i);
try {
TimeUnit.SECONDS.sleep(MAX_SLEEP_IN_SECONDS);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
}
);
log.info("CronJob ended :: jobKey : {}", jobKey);
log.info("===========================================");
}
}
package com.navercorp.quartz_setting.config;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.navercorp.quartz_setting.quartz.SampleJob;
@Configuration
public class ScheduleConfig {
/**
* Job을 실행 시키기 위한 JobDetail 정보를 Bean으로 등록
* @return JobDetail
*/
@Bean
public JobDetail scheduleJobDetail()
{
JobDataMap jobMap = new JobDataMap();
jobMap.put("Dev", "Hoon");
jobMap.put("Company", "NAVER");
return JobBuilder
.newJob(SampleJob.class).withIdentity("scheduleJob").usingJobData(jobMap).storeDurably()
.build();
}
/**
* JobDetail 정보를 바탕으로 Job을 호출할 Trigger 생성
* @return Trigger
*/
@Bean
public Trigger scheduleJobTrigger()
{
//cron
CronScheduleBuilder cronBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
return TriggerBuilder
.newTrigger().forJob(scheduleJobDetail()).withIdentity("scheduleTrigger").withSchedule(cronBuilder)
.build();
}
}
Quartz JDBC JobStore 설정
spring:
quartz:
wait-for-jobs-to-complete-on-shutdown: true #종료 시 실행 중인 작업이 완료 때까지 대기
job-store-type: jdbc
properties:
org:
quartz:
scheduler:
skipUpdateCheck: true
threadPool: #스레드 관련
class: org.quartz.simpl.SimpleThreadPool
threadCount: 5
plugin:
shutdownhook: #로깅 시스템이 초기화 되면 종료 후크 등록
class: org.quartz.plugins.management.ShutdownHookPlugin
cleanShutdown: true\\
jdbc:
initialize-schema: always
datasource:
url: jdbc:mysql://localhost:3306/test
username: test
password: test
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
logging:
level:
org.springframework.scheduling.quartz: debug
org.quartz: debug
실행 결과
2022-11-22 16:11:04.114 DEBUG 12821 --- [ restartedMain] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' returned by: restartedMain
2022-11-22 16:11:04.116 DEBUG 12821 --- [ restartedMain] o.s.s.quartz.LocalDataSourceJobStore : JobStore background threads started (as scheduler was started).
2022-11-22 16:11:04.116 DEBUG 12821 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore : MisfireHandler: scanning for misfires...
2022-11-22 16:11:04.116 INFO 12821 --- [ restartedMain] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED started.
2022-11-22 16:11:04.119 DEBUG 12821 --- [_MisfireHandler] o.s.s.quartz.LocalDataSourceJobStore : Found 0 triggers that missed their scheduled fire-time.
2022-11-22 16:11:04.124 INFO 12821 --- [ restartedMain] c.n.q.QuartzSettingApplication : Started QuartzSettingApplication in 1.887 seconds (JVM running for 2.384)
2022-11-22 16:11:04.137 DEBUG 12821 --- [SchedulerThread] org.quartz.core.QuartzSchedulerThread : batch acquisition of 1 triggers
2022-11-22 16:11:10.009 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' is desired by: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:10.009 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' is being obtained: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:10.011 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' given to: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:10.023 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' returned by: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:10.025 DEBUG 12821 --- [eduler_Worker-1] org.quartz.core.JobRunShell : Calling execute on job DEFAULT.scheduleJob
2022-11-22 16:11:10.027 INFO 12821 --- [eduler_Worker-1] c.n.quartz_setting.quartz.SampleJob : ===========================================
2022-11-22 16:11:10.027 INFO 12821 --- [eduler_Worker-1] c.n.quartz_setting.quartz.SampleJob : Develope by 김종훈 from NAVER
2022-11-22 16:11:10.027 INFO 12821 --- [eduler_Worker-1] c.n.quartz_setting.quartz.SampleJob : CronJob started :: sleep : 5 jobKey : DEFAULT.scheduleJob
2022-11-22 16:11:10.028 INFO 12821 --- [eduler_Worker-1] c.n.quartz_setting.quartz.SampleJob : CronJob Counting - 0
2022-11-22 16:11:10.041 DEBUG 12821 --- [SchedulerThread] org.quartz.core.QuartzSchedulerThread : batch acquisition of 1 triggers
2022-11-22 16:11:15.035 INFO 12821 --- [eduler_Worker-1] c.n.quartz_setting.quartz.SampleJob : CronJob Counting - 1
2022-11-22 16:11:20.012 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' is desired by: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:20.012 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' is being obtained: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:20.014 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' given to: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:20.025 DEBUG 12821 --- [SchedulerThread] o.q.i.jdbcjobstore.StdRowLockSemaphore : Lock 'TRIGGER_ACCESS' returned by: quartzScheduler_QuartzSchedulerThread
2022-11-22 16:11:20.026 DEBUG 12821 --- [eduler_Worker-2] org.quartz.core.JobRunShell : Calling execute on job DEFAULT.scheduleJob
2022-11-22 16:11:20.026 INFO 12821 --- [eduler_Worker-2] c.n.quartz_setting.quartz.SampleJob : ===========================================
DB Table 별 데이터 조회
SCHED_NAME |
TRIGGER_NAME |
TRIGGER_GROUP |
JOB_NAME |
JOB_GROUP |
DESCRIPTION |
NEXT_FIRE_TIME |
PREV_FIRE_TIME |
PRIORITY |
TRIGGER_STATE |
TRIGGER_TYPE |
START_TIME |
END_TIME |
CALENDAR_NAME |
MISFIRE_INSTR |
JOB_DATA |
quartzScheduler |
scheduleTrigger |
DEFAULT |
scheduleJob |
DEFAULT |
null |
1669102110000 |
1669102100000 |
5 |
ACQUIRED |
CRON |
1669101991000 |
0 |
null |
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- QRTZ_JOB_DETAIL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SCHED_NAME |
JOB_NAME |
JOB_GROUP |
DESCRIPTION |
JOB_CLASS_NAME |
IS_DURABLE |
IS_NONCONCURRENT |
IS_UPDATE_DATA |
REQUESTS_RECOVERY |
JOB_DATA |
quartzScheduler |
scheduleJob |
DEFAULT |
null |
com.navercorp.quartz_setting.quartz.SampleJob |
1 |
0 |
0 |
0 |
0xACED0005737200156F72672E71756172747A2E4A6F6244617 |
- QRTZ_FIRED_TRIGGES |
|
|
|
|
|
|
|
|
|
SCHED_NAME |
ENTRY_ID |
TRIGGER_NAME |
TRIGGER_GROUP |
INSTANCE_NAME |
FIRED_TIME |
SCHED_TIME |
PRIORITY |
STATE |
JOB_NAME |
JOB_GROUP |
IS_NONCONCURRENT |
REQUESTS_RECOVERY |
quartzScheduler |
NON_CLUSTERED1669101992328 |
scheduleTrigger |
DEFAULT |
NON_CLUSTERED |
1669102200012 |
1669102200000 |
5 |
EXECUTING |
scheduleJob |
DEFAULT |
0 |
0 |
quartzScheduler |
NON_CLUSTERED1669101992329 |
scheduleTrigger |
DEFAULT |
NON_CLUSTERED |
1669102210008 |
1669102210000 |
5 |
EXECUTING |
scheduleJob |
DEFAULT |
0 |
0 |
quartzScheduler |
NON_CLUSTERED1669101992330 |
scheduleTrigger |
DEFAULT |
NON_CLUSTERED |
1669102220007 |
1669102220000 |
5 |
EXECUTING |
scheduleJob |
DEFAULT |
0 |
0 |
- QRTZ_CRON_TRIGGERS |
|
|
|
|
|
|
|
|
|
|
|
|
SCHED_NAME |
TRIGGER_NAME |
TRIGGER_GROUP |
CRON_EXPRESSION |
TIME_ZONE_ID |
quartzScheduler |
scheduleTrigger |
DEFAULT |
0/10 * * * * ? |
Asia/Seoul |