728x90
Quartz 적용하기
스프링 부트와 쿼츠를 활용하여 매일 새벽 세시에 회원 테이블을 조회해서 마지막 로그인 시점이 6개월보다 이전이면 휴면 계정으로 처리하는 프로세스를 작성해 보자.
0. 쿼츠의 작동 방식
쿼츠 스케줄러는 작업을 주기적으로 실행하는 데 사용되는 강력한 라이브러리로, 여러 핵심 컴포넌트와 개념을 가지고 있다.
쿼츠의 작동 방식을 이해하려면 다음 개념들을 알아야 한다:
- Job:
- 정의: Job은 쿼츠가 실행할 작업을 정의한다.
- 특징: 사용자는 Job 인터페이스를 구현하고, execute() 메서드 안에 작업 내용을 정의한다.
- 역할: execute() 메서드는 스케줄러에 의해 트리거 될 때 호출된다.
- JobDetail:
- 정의: JobDetail은 Job의 인스턴스를 나타내며, Job에 대한 정보를 포함한다.
- 특징: Job 클래스, 식별자, 기타 설정을 포함할 수 있다.
- 역할: 스케줄러에 Job을 등록할 때 사용한다.
- Trigger:
- 정의: Trigger는 Job이 언제 실행될지를 결정한다.
- 특징: 한 번 실행 또는 반복 실행 등 다양한 스케줄링 구성이 가능하다.
- 역할: SimpleTrigger와 CronTrigger는 가장 일반적인 두 종류의 트리거다. SimpleTrigger는 매일 특정 시간에 실행되며, CronTrigger는 크론 표현식을 기반으로 복잡한 스케줄링을 지원한다.
- Scheduler:
- 정의: Scheduler는 Job과 Trigger를 관리하고 실행하는 역할을 한다.
- 특징: Scheduler는 쿼츠의 핵심 컴포넌트로, 여러 Job과 Trigger를 관리한다.
- 역할: Scheduler는 Job이 Trigger에 따라 실행되도록 조정한다.
이러한 컴포넌트들이 상호 작용하여 쿼츠는 다음과 같이 동작한다:
- 개발자는 Job 인터페이스를 구현하고, execute() 메서드에 작업 로직을 정의한다.
- JobDetail 객체를 생성하여 Job에 대한 정보를 설정한다.
- Trigger 객체를 생성하여 Job이 실행될 시간이나 조건을 정의한다.
- Scheduler를 사용하여 JobDetail과 Trigger를 등록하고, 스케줄러를 시작한다.
- 지정된 시간이 되면, 스케줄러는 Job의 execute() 메서드를 호출하여 작업을 실행한다.
이 과정을 통해 복잡한 타이밍과 조건을 가진 작업들을 효과적으로 관리하고 자동화할 수 있다.
1. 쿼츠 의존성 추가
- 먼저, 스프링 부트 프로젝트에 쿼츠를 사용하기 위해 spring-boot-starter-quartz 의존성을 추가한다.
implementation 'org.springframework.boot:spring-boot-starter-quartz'
2. 실행할 Job 구현
- 쿼츠에서 사용될 Job을 구현한다.
- 이 예제에서는 마지막 로그인이 6개월 전인 사용자를 휴면 계정으로 처리하는 Job이다.
@Component
@RequiredArgsConstructor
public class InactiveUserJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 휴면 계정 처리 프로세스
}
}
3. QuartzConfig 설정
- 쿼츠의 구성을 위해 QuartzConfig 클래스를 추가한다.
- 이 클래스는 Job과 Trigger를 설정한다.
지금 프로세스는 "매일 새벽 3시" 라는 특이사항때문에 CronTriggerFactoryBean을 사용하는게 더 적합하다.
SimpleTriggerFactoryBean을 사용하여 매일 특정 시간에 작업을 실행하는 것은 직관적이지 않다.
SimpleTrigger는 주로 반복 간격을 지정할 때 사용되며, 특정 시간에 작업을 시작하는 데는 적합하지 않다.
(하지만, 불가능하지는 않다. 아래 예시 코드와 비슷하게 창의적인 해결책을 사용하면 가능하다.)
- 이 코드는 CronTriggerFactoryBean을 사용한 예시 코드다.
@Configuration
public class QuartzConfig {
// InactiveUserJob에 대한 JobDetail 설정
@Bean
public JobDetailFactoryBean inactiveUserJobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(InactiveUserJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
// 매일 새벽 3시에 실행할 Trigger 설정
@Bean
public CronTriggerFactoryBean inactiveUserTrigger(JobDetail inactiveUserJobDetail) {
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(inactiveUserJobDetail);
trigger.setCronExpression("0 0 3 * * ?"); // 매일 새벽 3시에 실행
return trigger;
}
}
- 이 코드는 SimpleTriggerFactoryBean을 사용한 예시 코드다.
- 이 코드는 Calendar 객체를 사용하여 다음 새벽 3시의 정확한 시간을 계산하고, 현재 시간과 비교하여 이미 지났다면 다음 날로 설정한다. 이렇게 계산된 시간을 setStartDelay에 사용하여 첫 실행을 새벽 3시로 설정하고, 그 이후로는 매 24시간마다 반복한다.
@Configuration
public class QuartzConfig {
@Autowired
private ApplicationContext applicationContext;
// InactiveUserJob에 대한 JobDetail 설정
@Bean
public JobDetailFactoryBean inactiveUserJobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(InactiveUserJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
// 매일 새벽 3시에 실행할 Trigger 설정
@Bean
public SimpleTriggerFactoryBean inactiveUserTrigger(JobDetail inactiveUserJobDetail) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(inactiveUserJobDetail);
trigger.setRepeatInterval(24 * 60 * 60 * 1000); // 24시간 반복
// 첫 실행 시간을 새벽 3시로 설정
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// 이미 지난 시간이면 다음날로 설정
if (cal.getTime().before(new Date())) {
cal.add(Calendar.DAY_OF_MONTH, 1);
}
long startDelay = cal.getTimeInMillis() - System.currentTimeMillis();
trigger.setStartDelay(startDelay);
return trigger;
}
}
4. SchedulerRunner 추가
- 스케줄러를 시작하기 위해 ApplicationRunner를 구현하는 SchedulerRunner 클래스를 추가한다.
@Component
public class SchedulerRunner implements ApplicationRunner {
@Autowired
private Scheduler scheduler;
@Override
public void run(ApplicationArguments args) throws Exception {
scheduler.start();
}
}
5. 스케줄러 실행 여부 관리 (선택 사항)
- 스케줄러의 실행 여부를 'application.yml'을 통해 관리한다.
scheduler:
isInactiveUserOn: true
- 그리고 QuartzConfig 클래스에서 이 값을 참조하여 조건부로 스케줄러를 활성화한다.
@Value("${scheduler.isInactiveUserOn}")
private boolean isInactiveUserOn;
@Bean
public CronTriggerFactoryBean inactiveUserTrigger(JobDetail inactiveUserJobDetail) {
if (isInactiveUserOn) {
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(inactiveUserJobDetail);
trigger.setCronExpression("0 0 3 * * ?"); // 매일 새벽 3시
return trigger;
}
return null;
}
6. 마무리
이렇게 구성하여 쿼츠를 사용하면 복잡한 스케줄링 요구사항도 손쉽게 처리할 수 있으며, 특히 대규모 시스템이나 분산 환경에서 유리하다.
다음 포스팅에는 쿼츠를 이용해 매일 새벽 1시에 배치 작업을 trigger 하는 프로세스를 작성해보겠다.
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] 스프링 부트에서 파라미터화된 로깅{}과 String.format 사용법 (0) | 2023.11.15 |
---|---|
[Spring Boot] AOP를 활용한 로깅 구현: @EnableAspectJAutoProxy와 사용자 정의 Aspect 클래스 비교 가이드 (1) | 2023.11.13 |
[Spring Boot] 스프링 스케줄러 적용하기 (0) | 2023.11.11 |
[Spring Boot] Spring Batch, Spring Scheduler, Quartz의 차이 (0) | 2023.11.11 |
[Spring Boot] Spring Boot 3.X 버전에 Swagger 3 버전 적용하기 (1) | 2023.11.10 |