Programing/JAVA

Springboot Quartz clustering 적용방법, spring batch, shedlock

리커니 2023. 4. 18. 14:01
반응형

quartz를 사용하여 schedulering을 하는 어플리케이션을 이중화 하게 되면, 복수 개의 scheduler가 동작하기 때문에 문제를 야기 할 수 있습니다.

그래서 Clustering을 적용하여 하나의 scheduler만 동작하게 처리해야 합니다.

그 방법중에 하나가 Quartz clustering이고 shedlock 등의 라이브러리도 DB를 사용한 Clustering을 제공합니다.

 

Quartz clustering 적용방법

그럼 이제 quartz에 clustering을 적용하는 방법을 알아보도록 하겠습니다.

org.quartz.simpl.RAMJobStore 는 default 로 메모리를 사용한 스케쥴링이고,

org.quartz.impl.jdbcjobstore.JobStoreTX 가 DB를 활용한 스케쥴링 입니다.

 

 

1.quartz.properties 생성

quartz clustering을 위한 설정파일을 생성합니다.

설정 내용은 아래의 Link를 확인하세요.

 

Link : http://www.quartz-scheduler.org/documentation/quartz-1.8.6/configuration/ConfigJDBCJobStoreClustering.html

 

quartz-scheduler.github.io

Quartz website generated from quartz-scheduler.org-site repository (ALL PRs to that repo please)

www.quartz-scheduler.org

 

위의 Link를 참고하여 작성한 properties 파일의 내용입니다.

한글로 처리된 부분만 자신의 어플리케이션에 맞게 수정해주세요.

 

#============================================================================
# Configure Main Scheduler Properties  
#============================================================================
org.quartz.scheduler.instanceName = [스케쥴러 이름]
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool  
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = quartzDataSource
org.quartz.jobStore.tablePrefix = [스키마].qrtz_

org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000

#============================================================================
# Configure Datasources  
#============================================================================
org.quartz.dataSource.quartzDataSource.provider=hikaricp
org.quartz.dataSource.quartzDataSource.driver = org.postgresql.Driver
org.quartz.dataSource.quartzDataSource.URL = jdbc:postgresql://[데이터베이스 경로]
org.quartz.dataSource.quartzDataSource.user = [유저]
org.quartz.dataSource.quartzDataSource.password = [패스워드]
org.quartz.dataSource.quartzDataSource.maxConnections = 5
org.quartz.dataSource.quartzDataSource.validationQuery=select 1

 

이제 쿼즈에서 사용하는 테이블과 인덱스 등의 정보를 생성해 주어야 합니다.

아래의 quartz github로 이동하여 소스코드를 다운로드 받아도 되고, github에서 보여도 됩니다.

경로 : quartz-2.3.2\quartz-2.3.2\quartz-core\src\main\resources\org\quartz\impl\jdbcjobstore

 

Download Link : https://github.com/quartz-scheduler/quartz/releases/

 

Release Quartz 2.3.2 · quartz-scheduler/quartz

This a bug fix release containing fixes for: #508 : Error with H2 1.4.200 #505 : CronTrigger.getTriggerBuilder() changes misfire instruction from "ignore misfire" to "smart" #491 : StdJDBCDelegate...

github.com

 

Github Link : https://github.com/quartz-scheduler/quartz/tree/main/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore

 

GitHub - quartz-scheduler/quartz: Code for Quartz Scheduler

Code for Quartz Scheduler. Contribute to quartz-scheduler/quartz development by creating an account on GitHub.

github.com

 

이동하면 DB 종류에 따라 sql 파일이 존재하며, 자신의 DB 에 맞는 파일의 내용을 복사한 뒤 DB스크립트를 실행해 주시면 됩니다.

 

저의 경우 postgresql을 사용하기 때문에 tables_postgres.sql 파일을 내용을 스크립트에서 실행했습니다.

그럼 아래와 같은 테이블이 생성되고, 필요한 인덱스 및 기타 설정들이 추가되게 됩니다.

 

 

참고용으로 Config Class 를 보여드리겠습니다.

 

@Configuration
public class ScheduleConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleConfig.class);

    private SchedulerFactory schedulerFactory = new StdSchedulerFactory();

    @PostConstruct
    public void start() throws SchedulerException {
        LOGGER.info("[N]Start to Scheduler for send message and user unregister.");
        schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        TriggerKey sendMsgTriggerKey = new TriggerKey("sendMsg");
        scheduler.unscheduleJob(sendMsgTriggerKey);
        JobDetail sendMsg = JobBuilder.newJob(MsgJobClient.class).build();
        Trigger sendTrigger = TriggerBuilder.newTrigger().withIdentity(sendMsgTriggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule("30 0/10 * * * ?")).build();
        scheduler.scheduleJob(sendMsg, sendTrigger);

        TriggerKey unregisterTriggerKey = new TriggerKey("unregister");
        scheduler.unscheduleJob(unregisterTriggerKey);
        JobDetail unresisterUser = JobBuilder.newJob(UnregisterClient.class).build();
        Trigger unresisterTrigger = TriggerBuilder.newTrigger().withIdentity(unregisterTriggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?")).build();
        scheduler.scheduleJob(unresisterUser, unresisterTrigger);
    }
}

 

두개의 job이 동작하는 설정파일 입니다. 기존에는 unscheduleJob이 없이도 잘 동작하였으나, clustering 적용 시 문제가 되어 unscheduleJob을 추가하였습니다.

 

이제 프로젝트를 실행하면 아래와 같은 메시지가 표출되고, DB의 qrtz_scheduler_state 테이블을 보시면 데이터가 추가된 것을 확인하실 수 있습니다.

 

 

이제 프로젝트의 포트를 변경하여 .jar 파일을 만들어 2개의 프로젝트를 실행하면 하나의 프로젝트에서만 scheduler가 동작하는 것을 확인하실 수 있습니다.

 

yml으로 properties를 설정하려고 했는데 Document에서 찾지못해 properties 로 추가하였습니다. 

여타 다른 블로그에 나온 설정으로는 동작하지 않더군요, 아시는 분은 댓글 부탁드립니다.

반응형