본문 바로가기
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 별 데이터 조회

  • QRTZ_TRIGGER
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

'Framework > Spring-Quartz' 카테고리의 다른 글

(5) Quartz Trigger  (0) 2022.11.24
(3) Quartz DB Schema  (0) 2022.11.24
(2) Spring Scheduler vs Quartz  (0) 2022.11.24
(1) Quartz 정의  (0) 2022.11.24