반응형
해당 글에서는 Spring Boot Quartz에 대해 주요 메서드와 흐름, 처리과정에 대해 알아봅니다.
💡 [참고] Spring Boot Quartz의 이론에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
1) Spring Boot Quartz
💡 Spring Boot Quartz
- Java 기반의 오픈 소스 작업 '스케줄링 라이브러리'를 의미합니다. 이를 사용하면 특정시간에 작업을 실행하거나 특정 간격으로 작업을 수행할 수 있습니다.
-이를 사용하면 시스템의 자동화 및 효율성 향상에 기여하며 백그라운드 작업을 수행하는 서비스, 이메일 발송 스케줄링, 데이터베이스 백업 등에 활용될 수 있습니다.
1. 주요 클래스 및 인터페이스
용어 | 분류 | 설명 |
Job | 인터페이스 | 실행할 작업을 정의하는 인터페이스 |
JobDetail | 인터페이스 | 실행될 작업을 정의하고 구성하는 인터페이스 |
JobBuilder | 클래스 | JobDetail 인스턴스를 생성하는데 사용되는 유틸리티 클래스 |
JobListener | 인터페이스 | 작업의 생명 주기 동안 발생하는 이벤트를 처리하는 인터페이스 |
JobDataMap | 클래스 | 작업 실행시 필요한 데이터를 저장하는 맵 |
Trigger | 인터페이스 | 작업의 실행 시간을 결정하는 인터페이스 |
CronTrigger | 인터페이스 | 복잡한 실행 스케줄을 정의할 수 있는 Trigger 인터페이스 |
TriggerBuilder | 클래스 | Trigger 인스턴스를 생성하는데 사용되는 유틸리티 클래스 |
SimpleScheduleBuilder | 클래스 | 간단한 실행 스케줄을 정의할 수 있는 클래스 |
CronScheduleBuilder | 클래스 | 복잡한 실행 스케줄을 cron 표현식으로 정의할 수 있는 클래스 |
Scheduler | 인터페이스 | 작업과 트리거를 관리하고 실행하는 인터페이스 |
SchedulerFactory | 클래스 | Scheduler 인스턴스를 생성하는 클래스 |
2) Job
💡 Job
- 스케줄러에서 사용되는 Job은 JobDetail 객체를 구성하기 위해 JobBuilder로 구성하며, 해당 JobBuilder에는 Job의 인터페이스를 MyJob이라는 클래스에서 구현체로 ‘수행해야 하는 작업’을 작성하여 Builder를 구성하여 사용합니다.
1. Job
💡 Job
- Quarz에서 ‘실행 할 작업을 정의’하는 인터페이스입니다. 실행할 작업은 클래스를 생성하고 해당 Job 인터페이스의 구현체로 작업을 정의하여 사용합니다.
- Job 인터페이스를 구현하여 자신이 실행하고자 하는 작업에 대해서 정의를 할 수 있으며 Quartz의 생명 주기에 따라 주기적으로 실행이 됩니다.
void execute(org.quartz.JobExecutionContext jobExecutionContext) throws org.quartz.JobExecutionException;
2. JobDetail
💡 JobDetail
- Quatz 스케줄러에 의해 실행되는 작업을 정의합니다. 해당 객체는 JobBuilder를 통해 구성하며 실행하려는 Job의 이름, 그룹, 클래스 타입 등의 정보를 구성합니다.
💡 JobDetail 사용예시
- JobDetail 인스턴스를 구성합니다. 이는 JobBuilder로 구성하며 newJob()메서드를 통해 MyJob라는 Job을 추가하고 withIdentity()를 통해 그룹을 지정하여 객체를 구성합니다.
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
💡 [참고] JobDetail API Document
메서드 이름 | 반환 값 | 설명 |
getKey() | JobKey | Job의 Key를 반환합니다. |
getDescription() | String | Job의 설명을 반환합니다. |
getJobClass() | Class | Job의 구현 클래스를 반환합니다. |
getJobDataMap() | JobDataMap | Job의 data map을 반환합니다. |
isDurable() | boolean | Job이 지속적으로 저장되는지 여부를 반환합니다. |
isPersistJobDataAfterExecution() | boolean | Job이 실행 후 data map을 지속적으로 저장하는지 여부를 반환합니다. |
isConcurrentExectionDisallowed() | boolean | 동시에 여러 Job이 실행되는 것을 허용하는지 여부를 반환합니다. |
requestsRecovery() | boolean | Job이 실패한 경우 다시 실행하도록 설정되어 있는지 여부를 반환합니다. |
💡 [참고] Builder 패턴에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
3. JobBuilder
💡 JobBuilder
- Quartz 스케줄러에서 사용하는 유용한 유틸리티 클래스로 JobDetail 인스턴스를 생성하는데 사용됩니다.
- JobBuilder를 사용하면 JobDetail 객체를 쉽게 생성하고 작업의 이름, 그룹, 클래스 타입 등의 세부 정보를 설정할 수 있습니다.
💡 [참고] JobBuilder API Document
메서드 이름 | 반환 값 | 설명 |
build() | JobDetail | 이 JobBuilder가 정의한 JobDetail 인스턴스를 생성합니다. |
newJob() | JobBuilder | JobDetail을 정의하기 위한 JobBuilder 인스턴스를 반환합니다. |
newJob(Class jobClass) | JobBuilder | JobDetail을 정의하고, 실행할 Job의 클래스 이름을 설정하기 위한 JobBuilder 인스턴스를 반환합니다. |
ofType(Class jobClazz) | JobBuilder | Trigger가 이 JobDetail과 연결되어 발화될 때 인스턴스화되고 실행되는 클래스를 설정합니다. |
requestRecovery() | JobBuilder | '복구' 또는 '대체' 상황이 발생했을 때 Job이 다시 실행되어야 하는지 여부에 대한 스케줄러에 지시합니다. |
requestRecovery(boolean jobShouldRecover) | JobBuilder | '복구' 또는 '대체' 상황이 발생했을 때 Job이 다시 실행되어야 하는지 여부에 대한 스케줄러에 지시합니다. |
setJobData(JobDataMap newJobDataMap) | JobBuilder | 주어진 JobDataMap으로 JobDetail의 JobDataMap을 대체합니다. |
storeDurably() | JobBuilder | Job이 영구적으로 저장되어야 하는지 여부를 설정합니다. |
storeDurably(boolean jobDurability) | JobBuilder | Job이 영구적으로 저장되어야 하는지 여부를 설정합니다. |
usingJobData(JobDataMap newJobDataMap) | JobBuilder | 주어진 JobDataMap의 모든 데이터를 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, Boolean value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, Double value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, Float value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, Integer value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, Long value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
usingJobData(String dataKey, String value) | JobBuilder | 주어진 키-값 쌍을 JobDetail의 JobDataMap에 추가합니다. |
withDescription(String jobDescription) | JobBuilder | Job의 설명(사람이 이해할 수 있는)을 설정합니다. |
withIdentity(JobKey jobKey) | JobBuilder | JobKey를 사용하여 JobDetail을 식별합니다. |
withIdentity(String name) | JobBuilder | 주어진 이름과 기본 그룹을 가진 JobKey를 사용하여 JobDetail을 식별합니다. |
withIdentity(String name, String group) | JobBuilder | 주어진 이름과 그룹을 가진 JobKey를 사용하여 JobDetail을 식별합니다. |
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class) // Job의 구현 클래스 설정
.withIdentity("myJob", "group1") // Job의 identity 설정
.withDescription("This is my job") // Job의 설명 설정
.ofType(MyJob.class) // Job의 구현 클래스 설정
.requestRecovery(true) // Job이 실패한 경우 다시 실행하도록 설정
.storeDurably(true) // Job이 지속적으로 저장되도록 설정
.usingJobData("key", "value") // Job의 data map 설정
.build(); // 설정된 정보를 바탕으로 JobDetail 인스턴스 생성
4. JobListener
💡 JobListener
- 스프링 배치에서 제공하는 인터페이스로 배치 작업의 생명주기 동안 발생하는 이벤트를 처리합니다. 이 인터페이스를 구현함으로써 개발자는 배치 작업이 시작되거나 완료될 때마다 특정 작업을 수행하도록 할 수 있습니다.
- 예를 들어, 작업이 시작될 때 데이터베이스에 로그를 기록하거나, 작업이 완료된 후에 이메일 알림을 보내는 등의 작업을 수행할 수 있습니다. 이러한 기능은 배치 작업의 상태를 모니터링하고, 문제가 발생했을 때 즉시 알아차릴 수 있도록 돕습니다.
메서드 | 반환 값 | 설명 |
getName() | String | JobListener의 이름을 반환합니다. |
jobToBeExecuted() | void | Job이 실행되기 직전에 호출되는 메서드로, Job의 실행 준비 상황을 확인하거나 필요한 작업을 수행하는 데 사용할 수 있습니다. |
jobExecutionVetoed() | void | 다른 JobListener가 Job의 실행을 방해(veto)했을 때 호출되는 메서드입니다. |
jobWasExecuted() | void | Job의 실행이 완료된 후에 호출되는 메서드로, Job의 실행 결과를 로깅하거나 후속 작업을 수행하는 데 사용할 수 있습니다. |
public interface JobListener {
java.lang.String getName();
void jobToBeExecuted(org.quartz.JobExecutionContext jobExecutionContext);
void jobExecutionVetoed(org.quartz.JobExecutionContext jobExecutionContext);
void jobWasExecuted(org.quartz.JobExecutionContext jobExecutionContext, org.quartz.JobExecutionException e);
}
💡 사용예시
package com.adjh.testproject;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
/**
* Job 생명주기동안에 발생하는 이벤트를 처리합니다.
*
* @author : jonghoon
* @fileName : MyJobListener
* @since : 2/26/24
*/
public class MyJobListener implements JobListener {
@Override
public String getName() {
return "MyJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("Job 실행되기 이전에 수행됩니다.");
}
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
System.out.println("Job 실행이 실패하였을때 수행됩니다.");
}
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("Job 실행 이후에 수행됩니다.");
}
}
💡 사용예시
- 구성한 JobListener를 스케줄러 내에 추가하여 scheduler가 실행되는 동안 Job의 생명주기를 확인 할 수 있습니다.
public static void main(String[] args) throws SchedulerException {
JobDetail jobDetail = JobBuilder
.newJob(MyJob.class) // Job의 구현 클래스 설정
.withIdentity("myJob", "group1") // Job의 identity 설정
.withDescription("This is my job") // Job의 설명 설정
.ofType(MyJob.class) // Job의 구현 클래스 설정
.requestRecovery(true) // Job이 실패한 경우 다시 실행하도록 설정
.storeDurably(true) // Job이 지속적으로 저장되도록 설정
.usingJobData("key", "value") // Job의 data map 설정
.build(); // 설정된 정보를 바탕으로 JobDetail 인스턴스 생성
// Trigger 생성
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
// 스케줄러 생성 및 Job, Trigger 등록
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
MyJobListener myJobListener = new MyJobListener();
scheduler.getListenerManager().addJobListener(myJobListener); // JobListener 등록
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
5. JobDataMap
💡 JobDataMap
- Quartz 스케줄러에서 Job의 상태 데이터를 관리하는 데 사용되는 클래스입니다. 이 클래스는 키와 값의 쌍으로 이루어진 데이터를 저장하는 Map 인터페이스를 확장한 것입니다.
메서드 이름 | 반환 값 | 설명 |
getBooleanFromString(String key) | Boolean | JobDataMap에서 식별된 Boolean 값을 가져옵니다. |
getBooleanValue(String key) | boolean | JobDataMap에서 식별된 boolean 값을 가져옵니다. |
getBooleanValueFromString(String key) | boolean | JobDataMap에서 식별된 boolean 값을 가져옵니다. |
getCharacterFromString(String key) | Character | JobDataMap에서 식별된 Character 값을 가져옵니다. |
getCharFromString(String key) | char | JobDataMap에서 식별된 char 값을 가져옵니다. |
getDoubleFromString(String key) | Double | JobDataMap에서 식별된 Double 값을 가져옵니다. |
getDoubleValue(String key) | double | JobDataMap에서 식별된 double 값을 가져옵니다. |
getDoubleValueFromString(String key) | double | JobDataMap에서 식별된 double 값을 가져옵니다. |
getFloatFromString(String key) | Float | JobDataMap에서 식별된 Float 값을 가져옵니다. |
getFloatValue(String key) | float | JobDataMap에서 식별된 float 값을 가져옵니다. |
getFloatValueFromString(String key) | float | JobDataMap에서 식별된 float 값을 가져옵니다. |
getIntegerFromString(String key) | Integer | JobDataMap에서 식별된 int 값을 가져옵니다. |
getIntFromString(String key) | int | JobDataMap에서 식별된 int 값을 가져옵니다. |
getIntValue(String key) | int | JobDataMap에서 식별된 int 값을 가져옵니다. |
getLongFromString(String key) | Long | JobDataMap에서 식별된 Long 값을 가져옵니다. |
getLongValue(String key) | long | JobDataMap에서 식별된 long 값을 가져옵니다. |
getLongValueFromString(String key) | long | JobDataMap에서 식별된 long 값을 가져옵니다. |
putAsString(String key, boolean value) | void | 주어진 boolean 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Boolean value) | void | 주어진 Boolean 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, char value) | void | 주어진 char 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Character value) | void | 주어진 Character 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, double value) | void | 주어진 double 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Double value) | void | 주어진 Double 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, float value) | void | 주어진 float 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Float value) | void | 주어진 Float 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, int value) | void | 주어진 int 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Integer value) | void | 주어진 Integer 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, long value) | void | 주어진 long 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
putAsString(String key, Long value) | void | 주어진 Long 값을 Job의 데이터 맵에 문자열 버전으로 추가합니다. |
💡 사용예시
- JobDataMap 인스턴스를 생성하고 키-값 쌍으로 추가하는 예시이며 JobDetail을 구성하는데 setJobData() 메서드를 통해서 JobDataMap을 추가합니다.
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("key", "value");
JobDetail job = JobBuilder
.newJob(FcmJob.class) // Job 구현 클래스
.withIdentity("fcmSendJob", "fcmGroup") // Job 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Job") // Job 설명
.setJobData(jobDataMap)
.build();
3) Trigger
💡 Trigger
- 스케줄러에서 사용되는 Trigger는 SimpleTrigger와 CronTrigger로 나뉩니다.
- SimpleTrigger는 Trigger로 인스턴스화 해야합니다. 이는 TriggerBuilder를 통해 구성하며 withSchedule() 메서드를 통해서 SimpleScheduleBuilder를 구성합니다.
- CronTrigger는 Trigger 혹은 CronTrigger로 인스턴스화해야 합니다. 이는 TriggerBuilder를 통해 구성하며 withSchedule() 메서드를 통해서 CronScheduleBuilder를 구성합니다.
1. Trigger
💡 Trigger
- Quartz의 Trigger는 스케줄링 작업의 실행 시간을 결정하는 역할을 합니다. Trigger는 간단히 말해 작업이 언제 실행될지를 정의하는 것입니다.
- Trigger 역시 JobDetail 객체와 비슷하게 TriggerBuilder로 인스턴스를 생성합니다.
- Quartz는 SimpleTrigger와 CronTrigger 두 가지 주요한 Trigger를 제공합니다.
1. SimpleTrigger
- 특정 시간에 시작하여 주기적으로 작업을 실행하도록 설정할 수 있습니다. 이때 실행 주기와 반복 횟수를 설정해야 합니다
2. CronTrigger
- UNIX cron 표현식을 사용하여 작업 실행 스케줄을 정의할 수 있습니다. 복잡한 실행 스케줄을 정의할 수 있으므로, 매주 특정 요일에 실행되거나 매월 특정 날에 실행되는 등의 스케줄을 설정할 수 있습니다.
💡 SimpleScheduleBuilder 사용예시
- Trigger를 인스턴스화 할때 TriggerBuilder를 사용하여 구성합니다.
- TriggerBuilder에서는 simpleSchedule을 사용하여 구성하였고 10초마다 영원히 반복되는 트리거를 사용하였습니다.
// Trigger 생성
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
💡 CronScheduleBuilder 사용예시
- Trigger를 인스턴스화 할때 TriggerBuilder를 사용하여 구성합니다.
- TriggerBuilder에서는 cronSchedule을 사용하여 구성하였고 10초마다 반복되는 트리거를 사용하였습니다.
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("fcmSendTrigger", "fcmGroup") // Trigger 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Trigger") // Trigger 설명
.startNow()
.withSchedule(
CronScheduleBuilder
.cronSchedule("0/10 * * * * ?")
)
.build();
2. CronTrigger
💡 CronTrigger
- 작업을 주기적으로 실행하도록 설정하는 데 사용됩니다. 이는 UNIX의 cron 표현식을 사용하여 태스크의 실행 스케줄을 정의하며, 이를 통해 매우 복잡한 실행 스케줄을 설정할 수 있습니다.
- 예를 들어, 매주 특정 요일에 실행하거나, 매월 특정 날에 실행되는 등의 스케줄을 설정할 수 있습니다.
💡 사용예시
- 10초마다 수행하는 Trigger를 구성하였습니다.
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("fcmSendTrigger", "fcmGroup") // Trigger 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Trigger") // Trigger 설명
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();
3. TriggerBuilder
💡 TriggerBuilder
- Quartz 스케줄러에서 트리거를 생성하는 데 사용되는 유틸리티 클래스입니다. 이 클래스를 사용하면 트리거의 다양한 속성을 설정하고, 최종적으로 트리거 인스턴스를 생성할 수 있습니다.
- TriggerBuilder를 사용하여 트리거 이름, 그룹, 연관된 작업, 시작 시간, 종료 시간, 스케줄, 우선순위 등을 설정할 수 있습니다. 또한, JobDataMap을 사용하여 트리거가 실행될 때 필요한 추가 데이터를 제공할 수 있습니다.
TriggerBuilder는 SimpleTriggerBuilder와 CronTriggerBuilder 같은 여러 하위 클래스를 가지고 있습니다
1. SimpleTriggerBuilder
- 트리거가 특정 시간에 시작하여 일정한 간격으로 반복 실행되도록 설정할 수 있습니다
2. CronTriggerBuilder
- 복잡한 스케줄 패턴을 정의할 수 있습니다.
💡 [참고] TriggerBuilder API Document
메서드 | 반환값 | 설명 |
newTrigger() | TriggerBuilder | 새로운 TriggerBuilder를 생성합니다. |
withIdentity(String name) | TriggerBuilder | Trigger의 이름을 설정합니다. |
withIdentity(String name, String group) | TriggerBuilder | Trigger의 이름과 그룹을 설정합니다. |
forJob(JobDetail jobDetail) | TriggerBuilder | Trigger가 실행할 JobDetail을 설정합니다. |
forJob(String jobName) | TriggerBuilder | Trigger가 실행할 작업의 이름을 설정합니다. |
forJob(String jobName, String groupName) | TriggerBuilder | Trigger가 실행할 작업의 이름과 그룹을 설정합니다. |
startNow() | TriggerBuilder | Trigger를 즉시 실행하도록 설정합니다. |
startAt(Date startTime) | TriggerBuilder | Trigger가 시작되는 시간을 설정합니다. |
endAt(Date endTime) | TriggerBuilder | Trigger가 종료되는 시간을 설정합니다. |
withSchedule(ScheduleBuilder scheduleBuilder) | TriggerBuilder | Trigger의 스케줄을 설정합니다. |
modifiedByCalendar(String calendarName) | TriggerBuilder | Trigger가 수정되는 달력의 이름을 설정합니다. |
withPriority(int priority) | TriggerBuilder | Trigger의 우선순위를 설정합니다. |
usingJobData(String key, String value) | TriggerBuilder | Trigger의 JobDataMap에 문자열 값을 설정합니다. |
usingJobData(String key, int value) | TriggerBuilder | Trigger의 JobDataMap에 정수 값을 설정합니다. |
usingJobData(JobDataMap newJobDataMap) | TriggerBuilder | Trigger의 JobDataMap을 새로운 JobDataMap으로 설정합니다. |
build() | Trigger | 설정된 내용을 기반으로 Trigger를 생성합니다. |
4. SimpleScheduleBuilder
💡 SimpleScheduleBuilder
- 일정을 쉽게 만들 수 있는 도구입니다. 사용자는 특정 일정의 시작시간, 종료시간, 그리고 반복되는 패턴을 설정할 수 있습니다.
- 또한, 각 일정에 대한 설명, 위치, 참가자 등의 정보를 추가할 수 있습니다. SimpleScheduleBuilder를 사용하면 복잡한 일정도 간편하게 관리할 수 있습니다.
메서드 | 반환값 | 설명 |
simpleSchedule() | SimpleScheduleBuilder | SimpleScheduleBuilder의 인스턴스를 생성합니다. |
withIntervalInSeconds(int seconds) | SimpleScheduleBuilder | 작업의 실행 간격을 초 단위로 설정합니다. |
withIntervalInMinutes(int minutes) | SimpleScheduleBuilder | 작업의 실행 간격을 분 단위로 설정합니다. |
withIntervalInHours(int hours) | SimpleScheduleBuilder | 작업의 실행 간격을 시간 단위로 설정합니다. |
withIntervalInMilliseconds(long milliseconds) | SimpleScheduleBuilder | 작업의 실행 간격을 밀리초 단위로 설정합니다. |
withRepeatCount(int count) | SimpleScheduleBuilder | 작업의 반복 횟수를 설정합니다. |
repeatForever() | SimpleScheduleBuilder | 작업을 무한히 반복하도록 설정합니다. |
withMisfireHandlingInstructionIgnoreMisfires() | SimpleScheduleBuilder | misfire를 무시하고 작업을 실행하도록 설정합니다. |
withMisfireHandlingInstructionFireNow() | SimpleScheduleBuilder | misfire가 발생하면 즉시 작업을 실행하도록 설정합니다. |
withMisfireHandlingInstructionNextWithExistingCount() | SimpleScheduleBuilder | misfire가 발생하면 다음 반복 실행을 계획에 따라 수행하고, 반복 횟수는 변경하지 않습니다. |
withMisfireHandlingInstructionNowWithExistingCount() | SimpleScheduleBuilder | misfire가 발생하면 즉시 작업을 실행하고, 반복 횟수는 변경하지 않습니다. |
withMisfireHandlingInstructionNextWithRemainingCount() | SimpleScheduleBuilder | misfire가 발생하면 다음 반복 실행을 계획에 따라 수행하고, 남은 반복 횟수를 줄입니다. |
withMisfireHandlingInstructionNowWithRemainingCount() | SimpleScheduleBuilder | misfire가 발생하면 즉시 작업을 실행하고, 남은 반복 횟수를 줄입니다. |
5. CronScheduleBuilder
💡 CronScheduleBuilder
- Quartz 스케줄러에서 CronTrigger를 생성하는 데 사용되는 유틸리티 클래스입니다. 이 클래스를 사용하면 복잡한 작업 실행 스케줄을 cron 표현식을 사용하여 쉽게 정의할 수 있습니다.
// CronTrigger 생성
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("myCronTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * 1/1 * ? *"))
.build();
💡 cronExpression 사용 예시
* * * * *
- - - - -
| | | | |
| | | | +----- 요일 (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분 |
메서드 | 반환값 | 설명 |
cronSchedule(String cronExpression) | CronScheduleBuilder | cron 표현식을 사용하여 CronScheduleBuilder의 인스턴스를 생성합니다. |
cronSchedule(CronExpression cronExpression) | CronScheduleBuilder | CronExpression 객체를 사용하여 CronScheduleBuilder의 인스턴스를 생성합니다. |
dailyAtHourAndMinute(int hour, int minute) | CronScheduleBuilder | 매일 특정 시간에 작업을 실행하도록 설정합니다. |
weeklyOnDayAndHourAndMinute(int dayOfWeek, int hour, int minute) | CronScheduleBuilder | 매주 특정 요일에 특정 시간에 작업을 실행하도록 설정합니다. |
monthlyOnDayAndHourAndMinute(int dayOfMonth, int hour, int minute) | CronScheduleBuilder | 매월 특정 날에 특정 시간에 작업을 실행하도록 설정합니다. |
yearlyOnDayAndHourAndMinute(int dayOfYear, int hour, int minute) | CronScheduleBuilder | 매년 특정 날에 특정 시간에 작업을 실행하도록 설정합니다. |
inTimeZone(TimeZone timezone) | CronScheduleBuilder | 작업이 실행되는 시간대를 설정합니다. |
withMisfireHandlingInstructionIgnoreMisfires() | CronScheduleBuilder | misfire를 무시하고 작업을 실행하도록 설정합니다. |
withMisfireHandlingInstructionDoNothing() | CronScheduleBuilder | misfire가 발생하면 작업을 실행하지 않습니다. |
withMisfireHandlingInstructionFireAndProceed() | CronScheduleBuilder | misfire가 발생하면 작업을 즉시 실행하고, 다음 스케줄에 따라 계속 진행합니다. |
4) Scheduler
💡 Scheduler
- 스케줄러에서 사용되는 Scheduler는 StdSchedulerFactory를 통해 스케줄러를 가져와서 Scheduler Job을 구성합니다. 또한 Job의 생명주기를 관리하는 JobListener를 등록할 수 있습니다.
- Scheduler Job에는 Job과 Trigger가 등록이 됩니다.
1. Scheduler
💡 Scheduler
- 여러 작업(Job)을 관리하고 이들을 트리거(Trigger)에 따라 실행합니다. 스케줄러는 작업의 실행 시간, 빈도 등을 제어하며, 필요에 따라 작업을 일시 중지하거나 재개할 수 있습니다.
- 또한, 스케줄러는 작업의 실행 상태를 추적하고 작업 완료 후의 후속 작업을 관리하는 등의 역할을 합니다.
메서드 | 리턴 타입 | 설명 |
addCalendar(calName, calendar, replace, updateTriggers) | void | 주어진 Calendar를 스케줄러에 추가(등록)합니다. |
addJob(jobDetail, replace) | void | 주어진 Job를 스케줄러에 추가합니다. 이때 연관된 Trigger가 없습니다. |
addJob(jobDetail, replace, storeNonDurableWhileAwaitingScheduling) | void | 주어진 Job를 스케줄러에 추가합니다. 이때 연관된 Trigger가 없습니다. |
checkExists(jobKey) | boolean | 주어진 식별자를 가진 Job이 스케줄러 내에 이미 존재하는지 확인합니다. |
checkExists(triggerKey) | boolean | 주어진 식별자를 가진 Trigger가 스케줄러 내에 이미 존재하는지 확인합니다. |
clear() | void | 모든 스케줄링 데이터를 삭제합니다. 모든 Jobs, Triggers, Calendars를 삭제합니다. |
deleteCalendar(calName) | boolean | 스케줄러에서 특정된 Calendar를 삭제합니다. |
deleteJob(jobKey) | boolean | 스케줄러에서 특정된 Job을 삭제합니다. 이때 연관된 Triggers도 같이 삭제됩니다. |
deleteJobs(jobKeys) | boolean | 스케줄러에서 특정된 Jobs를 삭제합니다. 이때 연관된 Triggers도 같이 삭제됩니다. |
getCalendar(calName) | Calendar | 주어진 이름의 Calendar 인스턴스를 가져옵니다. |
getCalendarNames() | List<String> | 모든 등록된 Calendars의 이름을 가져옵니다. |
getContext() | SchedulerContext | 스케줄러의 SchedulerContext를 반환합니다. |
getCurrentlyExecutingJobs() | List<JobExecutionContext> | 이 스케줄러 인스턴스에서 현재 실행 중인 모든 Jobs의 JobExecutionContext 객체 목록을 반환합니다. |
getJobDetail(jobKey) | JobDetail | 주어진 키의 Job 인스턴스에 대한 JobDetail을 가져옵니다. |
getJobGroupNames() | List<String> | 모든 알려진 JobDetail 그룹의 이름을 가져옵니다. |
getJobKeys(matcher) | Set<JobKey> | 일치하는 그룹의 모든 JobDetails의 키를 가져옵니다. |
getListenerManager() | ListenerManager | 스케줄러의 ListenerManager에 대한 참조를 가져옵니다. 이를 통해 리스너를 등록할 수 있습니다. |
getMetaData() | SchedulerMetaData | 스케줄러 인스턴스의 설정과 기능을 설명하는 SchedulerMetaData 객체를 가져옵니다. |
getPausedTriggerGroups() | Set<String> | 일시 중지된 모든 Trigger 그룹의 이름을 가져옵니다. |
getSchedulerInstanceId() | String | 스케줄러의 인스턴스 ID를 반환합니다. |
getSchedulerName() | String | 스케줄러의 이름을 반환합니다. |
getTrigger(triggerKey) | Trigger | 주어진 키의 Trigger 인스턴스를 가져옵니다. |
getTriggerGroupNames() | List<String> | 모든 알려진 Trigger 그룹의 이름을 가져옵니다. |
getTriggerKeys(matcher) | Set<TriggerKey> | 주어진 그룹의 모든 Triggers의 이름을 가져옵니다. |
getTriggersOfJob(jobKey) | List<? extends Trigger> | 특정된 JobDetail과 연관된 모든 Triggers를 가져옵니다. |
getTriggerState(triggerKey) | Trigger.TriggerState | 특정된 Trigger의 현재 상태를 가져옵니다. |
interrupt(jobKey) | boolean | 현재 이 스케줄러 인스턴스 내에서 실행 중인 특정 Job의 중단을 요청합니다. 이때 Job은 InterruptableJob 인터페이스의 구현체여야 합니다. |
interrupt(fireInstanceId) | boolean | 현재 이 스케줄러 인스턴스 내에서 실행 중인 특정 Job 인스턴스의 중단을 요청합니다. 이때 Job은 InterruptableJob 인터페이스의 구현체여야 합니다. |
isInStandbyMode() | boolean | 스케줄러가 대기 모드인지를 보고합니다. |
isShutdown() | boolean | 스케줄러가 종료되었는지를 보고합니다. |
isStarted() | boolean | 스케줄러가 시작되었는지를 보고합니다. |
pauseAll() | void | 모든 트리거를 일시 중지합니다. |
pauseJob(jobKey) | void | 주어진 키의 JobDetail을 일시 중지합니다. |
pauseJobs(matcher) | void | 일치하는 그룹의 모든 JobDetails를 일시 중지합니다. |
pauseTrigger(triggerKey) | void | 주어진 키의 Trigger를 일시 중지합니다. |
pauseTriggers(matcher) | void | 일치하는 그룹의 모든 Triggers를 일시 중지합니다. |
rescheduleJob(triggerKey, newTrigger) | Date | 주어진 키의 Trigger를 제거(삭제)하고 새로 주어진 Trigger를 저장합니다. |
resetTriggerFromErrorState(triggerKey) | void | 특정된 Trigger의 현재 상태를 ERROR에서 NORMAL 또는 PAUSED로 재설정합니다. |
resumeAll() | void | 모든 트리거를 재개합니다. |
resumeJob(jobKey) | void | 주어진 키의 JobDetail을 재개합니다. |
resumeJobs(matcher) | void | 일치하는 그룹의 모든 JobDetails를 재개합니다. |
resumeTrigger(triggerKey) | void | 주어진 키의 Trigger를 재개합니다. |
resumeTriggers(matcher) | void | 일치하는 그룹의 모든 Triggers를 재개합니다. |
scheduleJob(jobDetail, triggersForJob, replace) | void | 주어진 job과 관련된 트리거 세트와 함께 job을 스케줄합니다. |
scheduleJob(JobDetail jobDetail, Trigger trigger) | Date | 주어진 JobDetail을 스케줄러에 추가하고, 주어진 Trigger와 연결합니다. |
scheduleJob(Trigger trigger) | Date | 주어진 Trigger로 작업을 스케줄링합니다. Trigger의 설정에 따라 Job이 실행됩니다. |
scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) | void | 주어진 모든 작업과 그에 관련된 Trigger들을 스케줄링합니다. |
setJobFactory(JobFactory factory) | void | Job 인스턴스를 생성하는 데 책임질 JobFactory를 설정합니다. |
shutdown() | void | Scheduler의 Trigger 발동을 중단하고, Scheduler와 관련된 모든 리소스를 정리합니다. |
shutdown(boolean waitForJobsToComplete) | void | Scheduler의 Trigger 발동을 중단하고, Scheduler와 관련된 모든 리소스를 정리합니다. |
standby() | void | Scheduler의 Trigger 발동을 일시 중단합니다. |
start() | void | Trigger를 발동시키는 Scheduler의 스레드를 시작합니다. |
startDelayed(int seconds) | void | 지정된 초 만큼 대기한 후 start()를 호출합니다. |
triggerJob(JobKey jobKey) | void | 주어진 JobKey를 가진 Job을 즉시 실행합니다. |
triggerJob(JobKey jobKey, JobDataMap data) | void | 주어진 JobKey를 가진 Job을 즉시 실행합니다. |
unscheduleJob(TriggerKey triggerKey) | boolean | 스케줄러에서 지정된 Trigger를 제거합니다. |
2. StdSchedulerFactory
💡 StdSchedulerFactory
- Quartz 스케줄러의 가장 일반적인 구현체입니다. 이 클래스는 Scheduler 인스턴스를 생성하고 초기화하는 역할을 합니다.
- 설정 파일이나 직접 전달된 Properties 객체를 이용해 스케줄러를 설정할 수 있습니다. 또한, 스케줄러가 사용하는 스레드 풀, JobStore 등의 구성 요소를 관리하고 설정합니다.
메서드 명 | 반환 타입 | 설명 |
getScheduler() | Scheduler | Scheduler 인스턴스를 반환합니다. 만약 아직 스케줄러가 초기화되지 않았다면 초기화를 수행한 후 반환합니다. |
getScheduler(String schedName) | Scheduler | 주어진 이름에 해당하는 Scheduler 인스턴스를 반환합니다. |
getAllSchedulers() | Collection<Scheduler> | 현재 팩토리에 의해 생성된 모든 Scheduler 인스턴스들을 반환합니다. |
initialize() | void | 기본 quartz.properties 파일을 사용해 스케줄러 팩토리를 초기화합니다. |
initialize(String filename) | void | 주어진 파일 이름의 properties 파일을 사용해 스케줄러 팩토리를 초기화합니다. |
initialize(Properties props) | void | 주어진 Properties 객체를 사용해 스케줄러 팩토리를 초기화합니다. |
5) 환경 구성
1. 의존성 주입
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-quartz:3.2.3' // Spring Boot Quartz
}
2. Job 구성
💡 Job 구성
- Job 인터페이스의 구현체로 구성합니다. 해당 클래스는 실제 데이터 처리를 위한 작업 내용을 명시합니다.
- Job 인터페이스에서 제공하는 메서드인 execute() 내에 실제 데이터 처리를 위한 Job을 구성합니다.
package com.adjh.multiflexapi.scheduler.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
/**
* 실제 데이터 처리를 위한 Job을 구성합니다.
*
* @author : lee
* @fileName : MyJob
* @since : 2/28/24
*/
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
System.out.println("실제 수행하는 Job 입니다.");
}
}
3. JobListener 구성
💡 JobListener 구성
- JobListener 인터페이스의 구현체로 구성합니다. 해당 클래스에서는 Job이 실행 직전, 실행 완료, 실행중 오류가 발생하였을 때의 생명주기를 관리하는 클래스입니다.
메서드 명 | 반환 값 | 설명 |
getName | String | JobListener의 이름을 반환합니다. |
jobToBeExecuted | void | Job이 실행되기 직전에 호출되는 메서드로, Job의 실행 준비 상황을 확인하거나 필요한 작업을 수행하는 데 사용할 수 있습니다. |
jobExecutionVetoed | void | 다른 JobListener가 Job의 실행을 방해(veto)했을 때 호출되는 메서드입니다. |
jobWasExecuted | void | Job의 실행이 완료된 후에 호출되는 메서드로, Job의 실행 결과를 로깅하거나 후속 작업을 수행하는 데 사용할 수 있습니다. |
package com.adjh.multiflexapi.scheduler.job;
import org.quartz.JobListener
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Job의 생명주기를 관리합니다.
*
* @author : lee
* @fileName : MyJobListener
* @since : 2/28/24
*/
public class MyJobListener implements JobListener {
@Override
public String getName() {
return "hello";
}
/**
* Job 실행 이전 수행
*
* @param jobExecutionContext
*/
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("[-] Job이 실행되기전 수행됩니다");
}
/**
* Job 실행 취소 시점 수행
*
* @param jobExecutionContext
*/
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
System.out.println("[-] Job이 실행 취소된 시점 수행됩니다.");
}
/**
* Job 실행 완료 시점 수행
*
* @param jobExecutionContext
* @param e
*/
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("[+] Job이 실행 완료된 시점 수행됩니다.");
}
}
4. SchedulerConfig 구성
💡 SchedulerConfig 구성
- 해당 클래스에서는 스케줄러를 구성하는 과정을 정의한 클래스입니다. Job, Trigger, Scheduler 인스턴스를 생성하여 일정 시간마다 수행하도록 구성합니다.
- 아래의 예시에서는 트리거에서 10초마다 반복처리 되어 수행되도록 구성되어 있습니다.
메서드 | 설명 |
jobProgress | 생성자 구성 및 초기 구성을 마치고 @PostConstruct 어노테이션에 따라 수행이 되며 스케줄러를 선택하여 호출하면 스케줄러가 수행이 되는 메서드입니다. |
simpleScheduler | SimpleScheduler를 이용하여서 스케줄러를 구성하는 메서드입니다. |
cronScheduler | CronScheduler를 이용하여 스케줄러를 구성하는 메서드입니다. |
package com.adjh.multiflexapi.scheduler;
import com.adjh.multiflexapi.scheduler.job.MyJob;
import com.adjh.multiflexapi.scheduler.job.MyJobListener;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
/**
* 스케줄러의 설정을 관리합니다.
*
* @author : lee
* @fileName : ScheduleConfig
* @since : 2/28/24
*/
@Configuration
public class SchedulerConfig {
private Scheduler scheduler;
public SchedulerConfig(Scheduler scheduler) {
this.scheduler = scheduler;
}
/**
* 스케줄러의 실제 처리 과정을 담당합니다.
*/
@PostConstruct
private void jobProgress() throws SchedulerException {
cronScheduler();
}
/**
* SimpleScheduler 구성 메서드
*
* @throws SchedulerException
*/
private void simpleScheduler() throws SchedulerException {
// [STEP1] Job 생성
JobDetail job = JobBuilder
.newJob(MyJob.class) // Job 구현 클래스
.withIdentity("myJob", "myGroup") // Job 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Job") // Job 설명
.build();
// [STEP2] Trigger 생성
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "myGroup") // Trigger 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Trigger") // Trigger 설명
.startNow()
.withSchedule(
SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// [STEP3] 스케줄러 생성 및 Job, Trigger 등록
scheduler = new StdSchedulerFactory().getScheduler();
MyJobListener myJobListener = new MyJobListener();
scheduler.getListenerManager().addJobListener(myJobListener);
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
/**
* CronScheduler 구성 메서드
*/
private void cronScheduler() throws SchedulerException {
// [STEP1] Job 생성
JobDetail job = JobBuilder
.newJob(MyJob.class) // Job 구현 클래스
.withIdentity("myJob", "myGroup") // Job 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Job") // Job 설명
.build();
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("fcmSendTrigger", "fcmGroup") // Trigger 이름, 그룹 지정
.withDescription("FCM 처리를 위한 조회 Trigger") // Trigger 설명
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();
// [STEP3] 스케줄러 생성 및 Job, Trigger 등록
scheduler = new StdSchedulerFactory().getScheduler();
MyJobListener myJobListener = new MyJobListener();
scheduler.getListenerManager().addJobListener(myJobListener);
scheduler.start();
scheduler.scheduleJob(job, cronTrigger);
}
}
6) 수행 과정
1. 서버 실행
💡 서버 실행
- 애플리케이션 서버가 실행되면 ‘Start Quartz Scheduler now’ 메시지가 출력되며 스케줄러가 수행됩니다.
2. JobListener 수행 : 콘솔 출력
💡 JobListener 수행 : 콘솔 출력
- Job이 실행하기 전, 후에 JobListener에서 수행이 됩니다.
3. Job 수행 : 콘솔 출력
💡 Job 수행 : 콘솔 출력
- Job이 수행이 되며 콘솔이 출력됩니다.
오늘도 감사합니다. 😀
반응형