스케줄링 & Spring Boot Quartz

Chooooo·2023년 12월 18일
0

인턴생활

목록 보기
17/19

😎 스케줄링

이번에 프로젝트에서 스케줄링을 해야하는 이벤트가 있기에 스케줄링에 대해 이해하고 Spring Boot Starter Quartz를 이용해 스케줄링을 구성해보고자 한다.

😊 스케줄링(Scheduling) & 배치 스케줄링(Batch Scheduling)

🎈 스케줄링(Scheduling)
일정한 시간 간격으로 반복적인 작업을 수행하는 도구를 의미한다.

  • 스케줄링을 이용하면 작업을 자동으로 수행하거나 주기적 혹은 일정 시간이 지난 후에 작업을 수행할 수 있어서 효율적인 작업 관리가 가능하다.

🎈 배치 스케줄링(Batch Scheduling)
배치 프로그램은 대량의 데이터를 처리하는 작업을 자동화하는 프로그램을 의미한다.

  • 이 대량의 데이터를 정해진 일정 또는 특정 이벤트 발생시간에 자동화 처리를 하기 위한 것을 의미한다.

😓 배치 프로그램과 스케줄러는 동일한 것?

  • 비슷한 기능을 가지고 있지만 동일한 것은 아니다. 실행방법과 목적에 큰 차이가 있다.
    배치 프로그램은 일괄 처리를 위한 프로그램이며 정해진 시간에 실행되지 않고 사용자의 명령이 있을 때 실행한다.

스케줄러는 정해진 시간에 자동으로 실행되는 프로그램이며 주기적으로 실행되는 작업을 설정할 수 있다.

👻 Spring Quartz

😉 Quartz란?

  • Java 기반의 오픈소스 작업 스케줄링 라이브러리를 의미한다. 이를 사용하면 특정시간에 작업을 실행하거나 특정 간격으로 작업을 수행할 수 있다.

  • 이를 사용하면 시스템의 자동화 및 효율성 향상에 기여하며 백그라운드 작업을 수행하는 서비스, 이메일 발송 스케줄링, 데이터베이스 백업 등에 활용될 수 있다.

🐳 Quartz의 기능과 사용목적

🎈Quartz의 기능

  1. 작업 스케줄링
  • 작업 예약 및 주기 설정 기능을 제공한다.
  1. 작업 실행 및 관리
  • 작업 실행, 중단, 재개, 삭제 기능을 제공한다.
  1. 작업 중단 및 재개
  • 작업 중단, 재개 기능을 제공한다.
  1. 여러 작업 동시 실행
  • 동시에 여러 작업 실행 기능을 제공한다.
  1. 작업 실행 결과 처리
  • 작업 실행 결과 처리 기능을 제공한다.

😊 Quartz의 사용 목적

  1. 쉬운 작업 구현
  • 스케줄링, 예약, 실행, 관리 등의 작업을 쉽게 구현할 수 있다.
  1. 다양한 작업 예약 및 실행
  • 다양한 작업을 예약하고 실행할 수 있다.
  1. 작업 실행 결과 처리 및 기록
  • 작업 실행 결과를 처리하고 이를 기록할 수 있다.
  1. 다양한 트리거 지원
  • 다양한 트리거(trigger)를 지원한다.
  1. 무료 사용
  • 오픈소스라서 무료 사용 가능

🐳 Quartz 클래스 및 인터페이스

  • Quartz에서는 JobTrigger를 함께 사용하여 Scheduler에 작업을 예약하고 Quartz는 자동으로 실행하도록 설정한다.

1. 클래스 및 인터페이스

용어 설명
🎈 Job : 실행할 작업에 대한 정보를 포함하는 클래스
🎈 JobDetail: Job 클래스의 인스턴스와 Job 실행에 필요한 추가 정보를 포함하는 클래스

  • Job을 실행하기 위한 상세 정보. JobBuilder에 의해서 생성된다.
  • JobData: Job에서 사용할 데이터를 전달하는 역할을 하는 객체이다.
    🎈 Trigger: Job 실행을 스케줄링하기 위한 클래스
  • Job을 실행하기 위한 조건(작업 실행 주기, 횟수 등)이다. 다수의 Trigger는 동일한 Job을 공유하여 지정할 수 있지만, 하나의 Trigger는 반드시 하나의 Job을 지정해야 한다. (TriggerBuilder를 통해 트리거 객체 생성)
    🎈 SimpleTrigger: 지정된 시간 간격으로 Job을 실행하기 위한 Trigger
    🎈 CronTrigger: Cron 표현식으로 Job을 스케줄링하기 위한 Trigger
    🎈 Scheduler : Job 실행과 Trigger 스케줄링을 관리하는 인터페이스 (JobDetail과 Trigger 정보를 이용해서 Job을 시스템에 등록하고, Trigger가 동작하면 지정된 Job을 실행시키는 역할을 하는 객체)
    🎈 SchedulerFactory : Scheduler 인스턴스를 생성하고 구성하기 위한 인터페이스

2. Job

  • Quartz에서 실행할 작업을 정의하는 인터페이스
  • Job 인터페이스를 구현하여 자신이 실행하고자 하는 작업에 대해서 정의를 할 수 있으며 Quartz의 생명 주기에 따라 주기적으로 실행된다.

Job 인터페이스는 execute 메서드를 정의하는데, execute 메서드의 파라미터인 JobExecutionContext에는 트리거 핸들링, 스케쥴에 의한 핸들링 등을 포함하여 런타임 환경에 대한 정보를 제공한다.

  • Override된 execute 메서드가 Scheduler에 의해 Job이 호출될 때 실행되는 부분
  • Job 구현체는 Scheduler에 의해 호출될 때마다 새로 생성된다.

JobExecutionContext

  • JobDetail 인스턴스가 Scheduler에 의해 실행될 때 넘어오고, 실행이 완료된 뒤에는 Trigger로 넘어간다.

3. Trigger

  • Job을 실행시키는 조건을 정의하는 인터페이스
  • 이를 통해 Job을 특정 시간에 실행하거나 주기적으로 실행하도록 설정할 수 있다.

트리거
SimpleTrigger : 특정 시간 또는 주기적으로 한 번 실행되는 트리거
CronTrigger: Cron 표현식을 사용하여 특정 시간에 실행되는 트리거
CalendarIntervalTrigger : 지정된 간격으로 주기적으로 실행되는 트리거
DailyTimeIntervalTrigger : 지정된 시간 범위 내에서 지정된 간격으로 주기적으로 실행되는 트리거

4. Scheduler

  • Job과 Trigger를 연결하고 Job을 실행 시키는 역할을 수행하는 인터페이스
  • SchedulerFactory에 의해 생성이 되는 서비스 핵심 객체이다. JobDetail과 Trigger를 관리한다.

메서드 종류

🐧 schedule(JobDetail jobDetail, Trigger trigger): JobDetail과 Trigger를 사용하여 Job을 스케줄링한다.

🐧 scheduleJob(JobDetail jobDetail, Trigger trigger) : schedule()과 같이 JobDetail과 Trigger를 사용하여 Job을 스케줄링합니다.

🐧 scheduleJob(Trigger trigger) : JobDetail 없이 Trigger만 사용하여 Job을 스케줄링한다.

🐧 rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) : 지정된 Trigger의 스케줄을 업데이트한다.

🐧 unscheduleJob(TriggerKey triggerKey) : 지정된 Trigger를 해제하여 Job 스케줄링을 취소한다.

🐧 pauseTrigger(TriggerKey triggerKey) : 지정된 Trigger를 일시 중지한다.

🐧 resumeTrigger(TriggerKey triggerKey) : 지정된 Trigger를 다시 시작한다.

🐧 pauseJob(JobKey jobKey) : 지정된 Job을 일시 중지한다.

🐧 resumeJob(JobKey jobKey) : 지정된 Job을 다시 시작한다.

👻 Trigger 상세

1. SimpleTrigger

  • 특정 시간에 한 번 실행하거나 주기적으로 실행할 수 있다.
  • 예를 들어, "매일 9시에 실행" 또는 "10초마다 실행" 이런 작업들

😁 속성

  • repeatCount : 작업이 실행될 횟수를 지정한다. 음이 아닌 정수 값이 될 수 있다. 0이 입력되면 작업이 무한히 실행된다.
  • repeatInterval : 작업이 실행되는 간격을 지정한다. 밀리초 단위로 측정될 수 있는 어떤 정수 값이든 될 수 있다.

사용예시

SimpleTrigger trigger = newTrigger()
    .withIdentity("trigger1", "group1")
    .startAt(startTime)
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(5))
    .build();
  1. new Trigger()를 통해 새로운 TriggerBuilder를 생성한다.
  2. .withIdentity("trigger1", "group1") : 트리거에 "trigger"이라는 고유한 이름과 group1이라는 그룹을 할당한다. 이를 통해 트리거를 식별하고 관리할 수 있다.
  • 여기까지 트리거 생성 및 식별자 설정
  1. startAt(startTime) : 트리거가 작동하기 시작할 시간을 설정
  • 트리거 시작시간 설정
  1. simpleSchedule(): 간단한 스케줄을 설정
  2. .withIntervalInSeconds(10): 작업이 반복되는 간격을 초 단위로 설정 여기서는 10초마다 작업이 반복된다.
  3. .withRepeatCount(5): 작업이 반복될 횟수를 설정. 여기서는 총 5회 반복되도록 설정

즉, Job이 시작시간(startTime)부터 10초 간격으로 5번 실행된다. repeatCount를 0으로 지정하면 무한히 실행된다.

2. CronTrigger

  • Cron 표현식을 사용하여 지정된 시간에 작업을 예약할 수 있다.
  • Cron 표현식은 분, 시, 일, 월, 요일 등의 필드를 사용하여 작업을 예약할 수 있다.
  • 예를 들어, "월요일부터 금요일까지, 매일 오후 3시에 실행"같은 작업을 예약할 수 있다.

😁 속성명

  • cronExpression : Cron 표현식을 나타내는 문자열, 이 표현식은 CronTrigger가 실행될 시간을 정의한다.
  • timeZone : CronTrigger가 실행될 때 사용할 시간대를 나타내는 문자열. 이 속성을 설정하지 않으면 기본값으로 서버의 시간대가 사용된다.
  • misfireInstruction : CronTrigger가 실행되지 않은 경우 동작을 지정하는 데 사용되는 상수. 예를 들어, misfireInstruction을 MISFIRE_INSTRUCTION_FIRE_ONCE_NOW로 설정하면 CronTrigger가 다음 실행 시간에 실행된다.
  • priority : 트리거의 우선 순위를 나타내는 숫자입니다. 높은 우선 순위 값을 가진 트리거는 낮은 우선 순위 값을 가진 트리거보다 먼저 실행된다.

사용예시

CronTrigger cronTrigger = TriggerBuilder.newTrigger()
    .withIdentity("myTrigger", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 10 ? * MON"))
    .build();
  1. Trigger 생성 및 식별자 설정
CronTrigger cronTrigger = TriggerBuilder.newTrigger()
    .withIdentity("myTrigger", "group1")
  • TriggerBuilder.newTrigger() : 새로운 TriggerBuilder를 생성한다.
  • .withIdentity("myTrigger", "group1") : 트리거에 "myTrigger"라는 고유한 이름과 "group1"이라는 그룹을 할당한다. 이를 통해 트리거를 식별하고 관리할 수 있다.
  1. Cron 스케줄 설정
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 10 ? * MON"))
  • CronScheduleBuilder.cronSchedule("0 0 10 ? * MON") : cron 표현식을 사용하여 트리거의 실행 스케줄을 설정한다.
  • "0 0 10 ? * MON" : cron 표현식으로, 이는 매주 월요일 오전 10시 0분 0초에 트리거가 작동하도록 지정한다.
  1. trigger 빌드
    .build();
    build(): 설정한 옵션들을 바탕으로 CronTrigger 객체를 생성한다.

즉, 매주 월요일 오전 10시에 실행되는 CronTrigger이다.

🐧 Cron 표현식

  • Cron 표현식은 리눅스 시스템에서 주기적인 작업을 자동으로 수행하기 위해 사용되는 문법이다.

👻 cron 표현식 구성

  • 분, 시, 일, 월, 요일, 순서로 입력된다.
*    *    *    *    *
-    -    -    -    -
|    |    |    |    |
|    |    |    |    +----- 요일 (0 - 6) (0이나 7이 일요일)
|    |    |    +---------- 월 (1 - 12)
|    |    +--------------- 일 (1 - 31)
|    +-------------------- 시 (0 - 23)
+------------------------- 분 (0 - 59)

cron 표현식 예시

👻 Cron Expression

  • * * * * * : 매 분
  • */30 * * * *: 30분마다
  • 30 5 * * * : 매일 오전 5시 30분
  • 30 5 * * 1 : 매주 월요일 오전 5시 30분
  • 30 5 1 * * : 매월 1일 오전 5시 30분

😓 Quartz의 실행주기

  • Quartz의 실행되는 단계

1단계 : 스케줄러 초기화

  • Quartz 스케줄러는 시작되면 먼저 스케줄러를 초기화한다. 이 초기화 과정에서는 스케줄러에 대한 설정을 로드하고, 자바 애플리케이션 컨텍스트와 연결한다.

2단계 : 작업 스케줄링

  • Quartz 스케줄러는 작업 스케줄링을 수행한다. 이 과정에서는 사용자가 등록한 작업을 실행할 시간을 계산하여 스케줄링 테이블에 등록한다.

3단계 : 작업 실행

  • 스케줄링 된 작업이 실행된다. Quartz 스케줄러는 스케줄링 된 작업을 실행하기 위해 쓰레드 풀을 사용한다.

4단계 : 작업 완료

  • 작업이 완료되면 Quartz 스케줄러는 작업이 완료되었다는 신호를 받는다. 이 신호를 받으면 스케줄링 테이블에서 작업을 제거한다.

5단계 : 스케줄러 종료

  • Quartz 스케줄러는 애플리케이션 종료 시점에 스케줄러를 종료한다. 이 과정에서는 스케줄링 된 작업을 모두 제거하고, 쓰레드 풀을 종료한다.

Spring Boot 환경에서 사용 예시

  1. quartz.properties의 구성 사항을 적용
  2. SchedulerFactory를 이용해 Scheduler를 만듦
  3. Scheduler에 JobDetail과 Trigger를 이용해 Job 스케줄링
  4. 정해진 시간마다 Scheduler가 Job을 호출하여 실행

DB설정

데이터베이스 설정을 따로 안하면, 기본으로 인메모리 기반으로 동작한다. 애플리케이션이 재시작하면 휘발성으로 데이터는 사라진다. DB에 저장하기 위해서는 properties 설정을 해야한다. 그리고 Quartz 연동 데이터베이스에 Quartz 관련 테이블을 생성하면 된다.

Quartz 관련 설정

  • spring.quartz.job-store-type : Quartz가 작업(Job)과 트리거(Trigger) 정보를 저장하는 방식을 지정. 기본값은 memory(인메모리) 방식이고 jdbc(데이터베이스에 저장)으로 설정할 수 있다.

  • spring.quartz.properties.org.quartz.scheduler.instanceName : Quartz 스케줄러 인스턴스의 이름을 지정한다. 여러 스케줄러 인스턴스를 사용할 때 구분하기 위한 목적으로 사용된다.

  • spring.quartz.properties.org.quartz.scheduler.instanceId : Quartz 스케줄러 인스턴스의 ID를 지정한다. AUTO로 설정하면 Quartz가 자동으로 고유 ID를 생성한다.

  • JobTrigger를 생성한다.
  • 이를 통해서 스케줄러를 생성하고 JobTrigger로 구성한다.
  • 최종적으로 스케줄러 작업을 구성한다.
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzExample {
    public static void main(String[] args) throws SchedulerException {
        // Job 생성
        JobDetail job = JobBuilder.newJob(MyJob.class)
            .withIdentity("myJob", "group1")
            .build();

        // Trigger 생성
        Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("myTrigger", "group1")
            .startNow()
            .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInSeconds(10)
                    .repeatForever())
            .build();

        // 스케줄러 생성 및 Job, Trigger 등록
        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.start();
        scheduler.scheduleJob(job, trigger);
    }
}

// 실행할 Job 클래스
public class MyJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Hello Quartz!");
    }
}

설명

1. Job 생성

JobDetail job = JobBuilder.newJob(MyJob.class)
    .withIdentity("myJob", "group1")
    .build();
  • JobBuilder.newJob(MyJob.class) : MyJob 클래스의 인스턴스를 사용하여 새로운 JobDetail 객체를 생성한다.
  • .withIdentity("myJob", "group1") : 작업에 "myJob"이라는 이름과 "group1"이라는 그룹을 지정한다.
  • .build() : 작업 세부 정보를 구축한다.

2. Trigger 생성

Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("myTrigger", "group1")
    .startNow()
    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
        .withIntervalInSeconds(10)
        .repeatForever())
    .build();
  • TriggerBuilder.newTrigger() : 새로운 Trigger 객체를 생성한다.
  • .withIdentity("myTrigger", "group1") : 트리거에 "myTrigger"라는 이름과 "group1"이라는 그룹을 지정한다.
  • .startNow() : 트리거를 즉시 시작한다.
  • .withSchedule(...) : 간단한 스케줄을 설정한다. 여기서는 10초 간격으로 무한 반복한다.
  • .build() : 트리거 구성을 완료한다.
  1. 스케줄러 생성 및 작업 등록
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
  • new StdSchedulerFactory().getScheduler() : StdSchedulerFactory를 사용하여 새로운 Scheduler 인스턴스를 생성한다.
  • scheduler.start() : 스케줄러를 시작한다.
  • scheduler.scheduleJob(job, trigger) : 생성한 작업과 트리거를 스케줄러에 등록한다.

즉 이 작업은 10초마다 "Hello Quartz"를 출력하는 Job을 실행하는 예시이다.

이제

Spring Quartz를 활용해서 스케줄링을 구현 해보자.

  • 단순 스케쥴링을 위해서 Quartz를 연동할 필요는 없을 것 같다. 간단한 스케쥴은 @Schedule 어노테이션으로 구현하자.

  • 복잡한 스케줄링 구현이 필요하다면 Quartz를 연동하면 좋을 것 같다.

profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글