📖 학습 자료 : https://adjh54.tistory.com/170

문제 상황

Quartz를 사용한 이유

Quartz vs Spring Batch

Quartz 를 활용한 스케줄링 생성 및 삭제

@RequiredArgsConstructor
@Service
public class ScheduleService {

    private final SchedulerFactoryBean schedulerFactoryBean;

		// 스케줄링 생성 로직
    private void addJob(JobRequest jobRequest, Class<? extends Job> jobClass) {
				// Job 을 실행시키는 Trigger 생성
        Trigger trigger = JobUtil.createTrigger(jobRequest);
        
        // Job 생성을 위한 JobDetail 객체 생성
        JobDetail jobDetail = JobUtil.createJob(jobRequest, jobClass);

        try {
		        // Job 스케줄링 수행
            schedulerFactoryBean.getScheduler().scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            throw new CustomCommonException(CommonErrorCode.INTERNAL_SERVER_ERROR);
        }
    }
    
}

@Builder
public record JobRequest (
        String name,
        String group,
        JobType jobType,
        Date startAt
) {
}

public enum JobType {
    ONE_TIME,
    MONTHLY
}
public class JobUtil {

    private JobUtil() {
    }

    public static Trigger createTrigger(JobRequest jobRequest) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobRequest.name(), jobRequest.group());

				// JobType 에 따른 Trigger의 스케줄 설정
				// 한번만 실행
        if (jobRequest.jobType().equals(JobType.ONE_TIME)) {
            return TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .startAt(jobRequest.startAt())
                    .build();
        // 월 단위 실행
        } else {
            return TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 1 * ?")) // 매월 1일 실행
                    .startNow()
                    .build();
        }
    }

    public static JobDetail createJob(JobRequest jobRequest, Class<? extends Job> jobClass) {
        JobKey jobKey = JobKey.jobKey(jobRequest.name(), jobRequest.group());

        JobDetail job = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .build();

        return job;
    }

}

스케줄링 작업을 위한 Job 클래스

@RequiredArgsConstructor
@Component
public class ChangeStageToCompletedJob implements Job {

    private final OrderService orderService;
    private final FactoryOrderService factoryOrderService;
    private final FactoryOrderEmailService factoryOrderEmailService;

    @Override
    public void execute(JobExecutionContext context) {
        Long orderId = Long.valueOf(context.getJobDetail().getKey().getName());

        Order order = orderService.getOrderById(orderId);

        if (!order.enableChangeStageToCompleted()) {
            return;
        }

        factoryOrderService.changeStageToCompleted(orderId);

        factoryOrderEmailService.sendEmailForChangeStageToCompleted(orderId);
    }
}