안녕하세요. J4J입니다.
이번 포스팅은 SpringBatch 사용하기 세 번째인 Quartz로 배치 만드는 방법에 대해 적어보는 시간을 가져보려고 합니다.
이전 글
[SpringBoot] SpringBatch 사용하기 (1) - Scheduler를 이용하여 Tasklet, Chunk 배치 만들기
[SpringBoot] SpringBatch 사용하기 (2) - Job Parameter 활용 및 동일 Job 반복 실행
Quartz란?
Quartz는 Spring에서 배치 프로세스를 만들 수 있는 오픈소스 라이브러리 중 하나로 작은 단위의 서비스부터 시작하여 큰 규모의 서비스들까지 모두 활용해 볼 수 있습니다.
이전 글들을 확인해보면 Spring Batch를 이용하여 배치를 만들어내는 것들을 볼 수 있었는데, Quartz를 사용한다면 Spring Batch의 역할을 대체할 수 있습니다.
하지만 개인적으로 단순 배치를 돌린다는 목적에서는 Spring Batch와 Quartz는 큰 차이를 경험할 수 없었습니다.
그래서 작은 규모의 서비스에서 배치를 돌린다고 할 때 둘 중 어떤 것을 꼭 사용해야 한다고 말할 순 없을 것 같습니다.
그럼에도 불구하고 SpringBatch 대신 Quartz를 사용해야 하는 경우가 있습니다.
Quartz GitHub을 확인해보면 Quartz는 클러스터링 기능을 제공해주고 있습니다.
즉, 큰 규모의 서비스들에서 배치를 만들어야 할 때 Scale-Out이 되어 있는 여러 배치 서버들에서 동일한 배치 비즈니스 로직이 모두 실행되는 것이 아니라 서버는 여러 대여도 한 번만 배치가 동작될 수 있도록 도와줍니다.
Job / Trigger / Scheduler
Quartz 소스를 작성하기 전 알고 있어야 되는 Job, Trigger, Scheduler라는 개념이 있습니다.
먼저 Job은 실행할 작업과 관련된 정보들이 담기는 곳입니다.
배치가 실행될 때 관련된 비즈니스 로직을 처리하는 곳이라고 생각할 수 있습니다.
Trigger는 Job의 실행 스케줄링을 어떤식으로 수행할 지에 대한 정보들이 담기는 곳입니다.
시간 단위로 스케줄링을 할지, cron 표현식으로 스케줄링을 할지에 대한 정보들을 정의할 수 있습니다.
Scheduler는 Job과 Trigger를 관리하는 곳입니다.
어떤 Job을 어떤 Trigger로 활용하여 동작시킬지 등을 정의할 수 있습니다.
사용 방법
개념에 대해 간단히 알게 되었으니 어떤 식으로 사용해볼 수 있는지 확인해 보겠습니다.
이전 글들에서 했던 것처럼 주기적으로 로그를 등록하는 배치를 Quartz를 활용하여 다음과 같이 작성해 볼 수 있습니다.
[ 1. dependency 추가 ]
dependencies {
// quartz
implementation 'org.springframework.boot:spring-boot-starter-quartz'
}
[ 2. Job 클래스 추가 ]
Job 클래스를 작성할 때 한 가지 주의사항은 어노테이션을 이용한 DI를 사용할 수 없다는 것입니다.
즉, 로그 등록을 위해서는 JpaRepository를 주입받아 활용해야 하는데 Job 클래스 내부에서 바로 주입받아 사용할 수 없기 때문에 아래에서 작성될 Schedule Config 에서 생성한 applicationContext를 활용하여 Bean을 호출해야 합니다.
package com.quartz.job;
import com.quartz.entity.LogEntity;
import com.quartz.repository.LogJpaRepository;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LogRegisterJob implements Job {
/**
* Job에서 실행될 작업을 정의한다.
*/
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// Schedule 설정에서 넣어둔 applicationContext를 가져와 Bean 호출에 활용
ApplicationContext applicationContext = (ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
// Job에서 @Autowired, @RequiredArgsConstructor 등의 주입이 불가하기 때문에 applicationContext 사용
LogJpaRepository logJpaRepository = applicationContext.getBean(LogJpaRepository.class);
// 로그 데이터 적재
logJpaRepository.save(
LogEntity
.builder()
.contents("logRegisterJobContents")
.createAt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.updateAt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.build()
);
}
}
[ 3. Schedule Config 클래스 추가 ]
package com.quartz.config;
import com.quartz.job.LogRegisterJob;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@RequiredArgsConstructor
public class LogRegisterScheduleConfig {
private final ApplicationContext applicationContext;
@Bean
public void start() throws SchedulerException {
// Job에서 Bean을 가져와 사용하기 위해 활용
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("applicationContext", applicationContext);
// Job을 이용하여 JobDetail을 생성
JobDetail jobDetail =
JobBuilder
.newJob(LogRegisterJob.class) // 실행될 Job
.setJobData(jobDataMap) // Job에서 활용될 jobDataMap 등록
.withIdentity("LogRegisterJobDetailName", "LogRegisterJobDetailGroup") // 식별을 위한 Identity 등록 (name, group)
.build();
// 스케줄링을 위한 Trigger 등록
Trigger trigger =
TriggerBuilder
.newTrigger()
.withIdentity("LogRegisterTriggerName", "LogRegisterTriggerGroup") // 식별을 위한 Identity 등록 (name, group)
.startNow() // 실행과 동시에 스케줄링 시작
// 5초 간격으로 무한히 스케줄링 처리
.withSchedule(
SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever()
)
.build();
// Scheduler로 Job과 Trigger 관리
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
}
}
위와 같이 설정 및 소스 작성을 완료해 보면 5초마다 로그 데이터가 적재되는 것을 확인할 수 있습니다.
하지만 위의 설정은 Quartz에서 제공하는 클러스터링 기능을 제공하지 않습니다.
다음 글에서 어떻게 클러스터링 기능까지 적용할 수 있는지 적어보겠습니다.
이상으로 SpringBatch 사용하기 세 번째인 Quartz로 배치 만드는 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Spring > SpringBoot' 카테고리의 다른 글
[Springboot] Jacoco를 이용하여 테스트 커버리지 확인하기 (1) | 2023.09.16 |
---|---|
[SpringBoot] SpringBatch 사용하기 (4) - Quartz로 클러스터링 처리하기 (1) | 2023.09.10 |
[SpringBoot] SpringBatch 사용하기 (2) - Job Parameter 활용 및 동일 Job 반복 실행 (0) | 2023.08.26 |
[SpringBoot] SpringBatch 사용하기 (1) - Scheduler를 이용하여 Tasklet, Chunk 배치 만들기 (0) | 2023.08.22 |
[SpringBoot] AWS Lambda와 API Gateway로 Serverless 구성하기 (4) - GitLab으로 Lambda 자동배포하기 (0) | 2023.05.10 |
댓글