모종닷컴

Quartz Job Scheduling 1편 - 소개 및 간단한 예제 본문

Programming/Spring

Quartz Job Scheduling 1편 - 소개 및 간단한 예제

모종 2022. 8. 14. 17:41
반응형

아주 예전부터 Quartz에 대한 글을 써야지 생각만 하고 어느새 잊어버렸는데요. 이번 회사 동료가 Quartz 적용을 한 발표를 하는데 너무 오래전에 본 내용이라 기억이 하나도 안나네요.. 그래서 기억좀 되살릴겸 Quartz 정리를 좀 해보았습니다. 

발표를 듣는 우리의 모습

Quartz Job Scheduling 란?

Quartz는 작은 독립형 애플리케이션부터 거대한 e-commerce 시스템에 이르기까지 거의 모든 Java 애플리케이션 내에 통합될 수 있는 풍부한 기능을 갖춘 오픈 소스 작업 스케줄링 라이브러리입니다. Quartz는 수십, 수백, 심지어 수만 개의 작업을 실행하기 위한 단순하거나 복잡한 일정을 만드는 데 사용될 수 있습니다. Quartz Scheduler에는 JTA 트랜잭션 및 클러스터링 지원과 같은 많은 엔터프라이즈급 기능이 포함되어 있습니다. Quartz는 Apache 2.0 라이센스로 자유롭게 사용가능합니다.
 

Quartz Job Scheduling 컴포넌트

Quartz Architecture
Quartz Shceduler Components

주요 컴포넌트 설명

  • Scheduler Factory – Scheduler Factory는 Scheduler 인스턴스 생성을 맡고있습니다. quartz.properties 파일의 내용을 기반으로 스케줄러 인스터스를 생성합니다. 
  • Scheduler – Quartz Scheduler의 메인 인터페이스입니다. Job의 세부 정보(JobDetail)과 Trigger 레지스트리를 관리합니다. 또한 Job과 관련된 Trigger가 발생되었을 때 Job 실행을 책입집니다.
  • Quartz Scheduler - Quartz의 핵심입니다. Scheduler 인터페이스를 간접구현하고 있으며, Trigger를 사용하여 Job을 스케줄링 하는 방법을 지니고 있습니다. 
  • Scheduler Thread – Trigger를 발생시키는 작업을 수행하는 스레드입니다. Job Store에 연결해 실행시킬 다음 Trigger를 가져옵니다.
  • Job – Job은 수행할 작업을 나타내기 때문에 실행이 될 task에서 구현해야 하는 가장 중요한 인터페이스입니다.
  • JobDetail - JobDetail은 주어진 Job 인스턴스의 상세 속성을 전달합니다. Quartz는 Job 인스턴스를 저장하지 않지만 JobDetail을 사용하여 Job 인스턴스를 정의할 수 있습니다. 
  • Trigger – 모든 트리거에 공통적인 속성을 가진 기본 인터페이스입니다. Job 실행을 예약하는 데 사용되는 메커니즘입니다. Job과 Trigger의 관계는 1:N입니다. 즉 많은 트리거가 동일한 Job을 가리킬 수 있지만, 하나의 트리거는 하나의 Job만 가리킬 수 있습니다.
  • ThreadPool – 실행이 될 Job은 스레드 풀에 전달됩니다.

Optional 컴포넌트

  • Job Store – Job과 Trigger에 대한 저장 메커니즘을 제공하는 클래스에 의해 구현되는 인터페이스입니다. 저장은 메모리와 디비로 나뉘는 것 같습니다.
  • Job Listener - JobDetail이 실행될 때 알림을 받을 클래스에 의해 구현되는 인터페이스입니다. 스케줄러에 연결되어 있으며 실행 전후에 호출되는 메서드가 있습니다.
  • Job Trigger - JobListener와 유사합니다. 트리거가 실행될 때 알림을 받고자 하는 클래스에 의해 구현되는 인터페이스입니다.
 

https://www.javarticles.com/2016/03/quartz-scheduler-model.html

 

Quartz Scheduler Model - Java Articles

In this article we will brief you about the internal architecture of Quartz Scheduler. We will first review the main components of a Quartz Scheduler and then look into its model. Main Quartz Scheduler Components Job and Trigger represent the ‘what’ is

www.javarticles.com

https://examples.javacodegeeks.com/enterprise-java/quartz/java-quartz-architecture-example/

 

Java Quartz Architecture Example

Interested to learn more about Java Quartz? Then check out our detailed example on Java Quartz Architecture!

examples.javacodegeeks.com


Spring Boot에서도 지원해주는 Quartz Scheduler

Spring Boot는 Quartz 스케줄러 작업에 몇 가지 편의를 제공하기 위해 spring-boot-starter-quartz 를 제공합니다. 만약 Quartz가 이용가능하다면 직접 빈으로 등록할 필요없이 스프링 부트에서 Scheduler는 자동으로 구성되도록 되어있습니다. Scheduler 뿐만 아니라 다음 유형의 빈은 자동으로 생성됩니다. JobDetail, Calendar, Trigger
 
기본적으로 JobStore는 인메모리 기반으로 사용되도록 설정되었지만 추가 설정을 통해 JDBC 기반 스토어도 사용 가능합니다.
spring.quartz.job-store-type=jdbc

jdbc 스토어가 사용될 때 테이블 생성이 필요할 텐데 아래 프로퍼티를 설정하면 시작하면서 초기화될 것입니다.

spring.quartz.jdbc.initialize-schema=true

 

Quartz 라이브러리와 함께 표준 스크립트를 사용하여 데이터베이스가 초기화되는데, 커스텀한 스크립트를 적용하고 싶다면 spring.quartz.jdbc.shcema를 사용하면 됩니다.

Quartz Scheduler 구성은 Quartz 설정관련 프로퍼티를 이용하여 커스터마이징 할 수 있습니다. 

https://docs.spring.io/spring-boot/docs/2.0.0.M3/reference/html/boot-features-quartz.html

 

39. Quartz Scheduler

Spring Boot offers several conveniences for working with the Quartz scheduler, including the spring-boot-starter-quartz ‘Starter’. If Quartz is available, a Scheduler will be auto-configured (via the SchedulerFactoryBean abstraction). Beans of the foll

docs.spring.io


Quartz 사용해보기

spring-boot-starter-quartz를 사용하면 Scheduler는 자동으로 등록된다 했으니 Job이랑 Trigger만 생성해주면 자동 생성된 Scheduler에 자동 등록된다는 것으로 이해했으므로 Job과 Trigger만 생성해줘 보겠습니다.

Dependency 

implementation 'org.springframework.boot:spring-boot-starter-quartz'

Property Set

jobStore는 두 가지 유형이 가능합니다. in-memory에 올려서 테스트할 거라면 추가 프로퍼티 세팅은 필요 없으나, jdbc 기반을 사용한다면 아래와 같이 설정을 하도록 해야 합니다. initialize-schema 프로퍼티가 스프링 부트 문서에 나와있는 부분이랑 좀 달랐어요.. 설명을 대충 보니 always를 쓰면 될 것 같아요

## Quartz Properties
  quartz:
    job-store-type: jdbc # jdbc
    jdbc:
      initialize-schema: always # Quartz 필수 테이블 자동 생성

Job 정의하기

class TestJob: QuartzJobBean() {
    override fun executeInternal(context: JobExecutionContext) {
        val jobDateMap = context.jobDetail.jobDataMap

        log.info { "name = ${jobDateMap["name"]}, 현재 시각 : ${LocalDateTime.now()}" }
    }
}

JobListener 추가

@Component
class TestJobListener : JobListener {

    override fun jobExecutionVetoed(context: JobExecutionContext?) {

    }

    override fun getName(): String = this::class.java.name

    override fun jobToBeExecuted(context: JobExecutionContext) {
        val jobName = context.jobDetail.jobClass.name
        log.info("$jobName 실행 예정.")
    }

    override fun jobWasExecuted(context: JobExecutionContext, jobException: JobExecutionException?) {
        val jobName = context.jobDetail.jobClass.name
        log.info("$jobName 실행 완료")
    }
}

JobDetail, Trigger 생성 &  JobListener 등록

@Configuration
class QuartzConfig(
    @Lazy val schedulerFactoryBean: SchedulerFactoryBean,
    val testJobListener: TestJobListener
) {
    @PostConstruct
    fun addListeners() {
        schedulerFactoryBean.scheduler
            .listenerManager
            .addJobListener(testJobListener)
    }

    @Bean
    fun testJobDetail(): JobDetailFactoryBean {
        val jobDataMap = JobDataMap()
        jobDataMap["name"] = "mojong"

        return JobDetailFactoryBean().apply {
            setJobClass(TestJob::class.java) // 어떤 Job에 대한 JobDetail 인지 명시
            setDescription("Invoke Test Job") // 설명
            setDurability(true) // 필수인 듯
            setJobDataMap(jobDataMap)
        }
    }

    @Bean
    fun testJobTrigger(jobDetail: JobDetail): SimpleTriggerFactoryBean {
        return SimpleTriggerFactoryBean().apply {
            setJobDetail(jobDetail)
            setRepeatInterval(60 * 1000) // 1분마다
            setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY) // 계속
        }
    }
}

테스트 결과

잘 실행이 되는 것 같습니다. jdbc 유형의 jobStore를 사용하면 QRTZ_JOB_DETAILS 테이블과 QRTZ_TRIGGERS 테이블, QRTZ_SIMPLE_TRIGGERS 테이블을 한번 구경해보도록 하죠

이번 글에서는 Quartz Scheduler에 대한 간단하게 이해하고, Spring에 적용해보는 예제를 다뤄보았습니다. 다음 2편에서는 Quartz를 좀 더 다양하게 활용하는 글을 써보도록 하겠습니다. 

긴 글 읽어주셔서 감사합니다. 다음 편에 보아요.

반응형