주기적인 작업을 처리하기 위한 Spring 기능들을 찾아보면서.
매 시간 또는 매월 마지막 금요일 실행할 무언가를 정의
@SpringBootApplication
@EnableScheduling
public class DemoApplication {..}
@Component
public class PeriodicTask {
// 5초마다 실행, 1초에 2번 실행
//@Scheduled(cron = "0/5 * * * * ?")
@Scheduled(fixedDelay = 500)
public void everyFiveSeconds(){...}
}
// @EnableScheduling 사용 x, Quartz 의존성을 추가해야한다.
/**
* @interface Job
* 우리가 실행 할 로직을 포함하는 클래스를 구현한다
* execute @Override
*/
public class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {...}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws SchedulerException {
SpringApplication.run(DemoApplication.class, args);
OnStartup();
}
private static void OnStartup() throws SchedulerException {
/**
* jobDetail
* job 인스턴스와 관련 데이터를 정의, 이름과 그룹으로 구성괸 JObKey로 식별됨
*/
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.usingJobData("param", "value")
.build();
/**
* @param trigger
* 작업이 실행되는 일정을 정의
* 트리거는 하나의 작업에만 연결
* 1초 위에 trigger가 발생하는 trigger을 정의
*/
Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(1)
.atZone(ZoneId.systemDefault()).toInstant());
Trigger trigger = TriggerBuilder.newTrigger()
.startAt(afterFiveSeconds)
.build();
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
/**
* schedular.start()
* Scheduler 가 대기 모드에서 초기화
* scjeduler.scheduleJob()
* job 실행을 예약
*/
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
Quartz는 JobDetail, Trigger, 기타정보를 JobStore에 저장한다. 기본 in-memory 이므로 즉, 예약된 작업이 있고 실행되기 전에 응용 프로그램을 종료(예: 다시 시작하거나 충돌할 때)하면 다시는 실행되지 않는다. JDBC-JobStore에 저장하기 위해 다음 설정을 사용
다음과 같은 테이블 생성
# application.yaml
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always
이를 위해서는 @Bean, @EnableScheduling 설정을 해야한다.
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) throws SchedulerException {...}
/**
* 기존 코드
* SchedulerFactory schedulerFactory = new StdSchedulerFactory();
* Scheduler scheduler = schedulerFactory.getScheduler();
*/
@Bean
public Scheduler scheduler(SchedulerFactoryBean factory) throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
scheduler.start();
return scheduler;
}
@Bean
public CommandLineRunner run(Scheduler scheduler) {
return (String[] args) -> {
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.usingJobData("param", "value") // add a parameter
.build();
Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5)
.atZone(ZoneId.systemDefault()).toInstant());
Trigger trigger = TriggerBuilder.newTrigger()
.startAt(afterFiveSeconds)
.build();
scheduler.scheduleJob(job, trigger);
};
}
@Scheduled, implements Job 을 통해 생성된 Job은 서로 다른 스레드 풀에서 시작된다.
@Scheduled 는 하나의 스레드만 포함
@Configuration
public class SchedulingConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
// @Scheduled 만 변경
threadPoolTaskScheduler.setPoolSize(10);
threadPoolTaskScheduler.setThreadNamePrefix("modified-my-scheduled-task-pool");
threadPoolTaskScheduler.initialize();
taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
# application.yaml
spring:
quartz:
properties:
org.quartz.threadPool.threadNamePrefix: Modified-My-quartz-Worker
org.quartz.threadPool.threadCount: 25
설정 후
매개변수가 다른 스케줄러를 생성하는 경우 여러개의 SchedulerFactoryBreans를 정의해야 한다.
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) throws SchedulerException {
SpringApplication.run(DemoApplication.class, args);
}
/**
* @param dataSource : JDBCJobStore 를 사용할 때
*/
@Bean(name = "CustomSchedulerFactory1")
public SchedulerFactoryBean customSchedulerFactoryBean1(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// Properties 설정
Properties properties = new Properties();
properties.setProperty("org.quartz.threadPool.threadNamePrefix", "my-custom-scheduler1-");
factory.setQuartzProperties(properties);
factory.setDataSource(dataSource);
return factory;
}
@Bean(name = "CustomSchedulerFactory2")
public SchedulerFactoryBean customSchedulerFactoryBean2(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
Properties properties = new Properties();
properties.setProperty("org.quartz.threadPool.threadNamePrefix", "my-custom-scheduler2-");
factory.setQuartzProperties(properties);
factory.setDataSource(dataSource);
return factory;
}
@Bean("CustomScheduler1")
public Scheduler customScheduler1(@Qualifier("CustomSchedulerFactory1") SchedulerFactoryBean factory) throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
scheduler.start();
return scheduler;
}
@Bean("CustomScheduler2")
public Scheduler customScheduler2(@Qualifier("CustomSchedulerFactory2") SchedulerFactoryBean factory) throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
scheduler.start();
return scheduler;
}
@Bean
public CommandLineRunner run(@Qualifier("CustomScheduler1") Scheduler customScheduler1,
@Qualifier("CustomScheduler2") Scheduler customScheduler2) {
return (String[] args) -> {
Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5)
.atZone(ZoneId.systemDefault()).toInstant());
/**
* SchedulerFactoryBean -> Scheduler -> CommandLineRunner
*
* JobDetail(Value1) -> Trigger
* JobDetail(Value2) -> Trigger
*/
JobDetail jobDetail1 = JobBuilder.newJob(SimpleJob.class)
.usingJobData("param", "value1")
.build();
Trigger trigger1 = TriggerBuilder.newTrigger()
.startAt(afterFiveSeconds)
.build();
customScheduler1.scheduleJob(jobDetail1, trigger1);
JobDetail jobDetail2 = JobBuilder.newJob(SimpleJob.class)
.usingJobData("param", "value2").build();
Trigger trigger2 = TriggerBuilder.newTrigger()
.startAt(afterFiveSeconds).build();
customScheduler2.scheduleJob(jobDetail2, trigger2);
};
}
}
실행할 무언가를 정의
ref
Quartz
https://hackernoon.com/how-to-schedule-jobs-with-quartz-in-spring-boot
https://medium.com/@manvendrapsingh/introduction-to-quartz-scheduling-af9b01708c24