Spring 프레임워크 기반의 웹 프로그램에서 시간 주기에 따라 작업을 수행하는 것은 유명 오픈소스 Quartz 을 사용하여 손쉽게 구현할 수 있다. Spring 프레임워크 역시 추상화를 통하여 Quartz 스케줄러를 위한 인스턴스 생성을 위한 FactoryBean 및 (MethodInvokingFactoryBean을 사용하여) 컨텍스트에 존재하는 Bean 함수 호출을 할 수 있게 지원하고 있다.
안정성을 중요시하는 요즘에 서버 이중화는 그리 특별한 것이 아니며 하나 이상의 프로그램 서버에 스케줄러 기반의 배치 작업을 포함하는 웹 프로그램의 경우 해결해야 하는 몇가지 이슈가 있다.
- 서버 인스턴스 A, B 가 있는 경우 오직 인스턴스 A 에 스케줄러 설정 포함하여 운영하는 방식을 많이 사용한다. 이경우 인스턴스 A 가 다운된 상태의 경우 스케줄러 작업이 진행되지 않는 이슈가 있음.
- Quartz Jdbc Clustering 의 경우 스케줄러 작업에서 스프링에 등록된 서비스를 호출하여 작업을 하는 경우 이부분에 대한 처리가 잘 되지 않음. (구현 방법이 명확하게 기술된 자료를 확인하지 못함)
이러한 어려움들은 몇가지 문서들을 기초로하여 해결 할 수 있었다. 참고로 이글에서는 어노테이션이 아닌 XML 을 이용한 설정으로 구현하였다. Spring 프레임워크 기반에서 Quartz 스케줄러를 이용한 작업은 아래 3가지를 정의하여 구현할 수 있다.
Quartz Scheduler
❶ 특정 Job 을 정의하는 JobDetail 정의
Quartz 스케줄러에서 실행될 작업을 담는 Job 정의하는 JobDetail 인스턴스는 JobBuilder API를 사용하면 쉽게 생성할 수 있다. Spring 에서는 ⑴ 등록된 다른 Bean 의 함수를 호출하는 작업을 위한 MethodInvokingJobDetailFactoryBean 클래스와 ⑵ 실행되는 작업은 반듯이 구현해야하는 인터페이스 org.quartz.Job 을 구현하는 JobDetail 인스턴스 생성을 돕는 JobDetailFactoryBean 클래스가 있다.
❷ Trigger 정의
스케줄러를 어떤 방식, 어떤 주기로 작동할 지를 정의한다. Trigger 은 ⑴ start time, end time, interval time, repeat times 주기를 설정하는 SimpleTrigger 과 ⑵ Cron 형식으로 일정 주기를 지정하는 CronTrigger 가 있다.❸ Quartz Scheduler 정의
❶ 과 ❷ 입력하여 작업을 실행한다.
그림1. Quartz Scheduler 구성요소 |
그림2. Quartz Scheduler 내부 구조 |
테스트는 다음 환경에서 진행되었다.
테스트 환경
- Springframework 5.3.6
- Quartz 2.3.2
- Apache Tomcat 8.5.57
- JAVA 1.8 (인프라 호환성 유지를 위하여 낮은 버전을 사용)
- HW : Macbook Pro 2020 ( 2.3GHz 8Core Intel Core i9 16GB Memory)
JDBC 을 이용한 Clustering 과정에서 경험한 것들
1. Schema 생성하기
- Quartz 2.1.x : https://github.com/quartz-scheduler/quartz/tree/quartz-2.1.x/docs/dbTables
- Quartz 2.3.x : https://github.com/quartz-scheduler/quartz/tree/quartz-2.3.x/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore
2. Job Detail 설정
Quartz 2.1.7 버전의 경우 JobDetail 의 JobDataMap 값이 Job 구현 클래스에 자동으로 바인딩되지 않아 Job 구현 클래스에서 executeInternal() 구현시 인자로 전달되는 JobExecutionContext 에서 JobDataMap 데이터를 꺼내어 설정하는 작업이 필요했다. Quartz 2.3.2 버전에서는 자동으로 바인인되었다. 주의할 것은 JobDetail 객체를 JobDetailFactoryBean 사용하여 정의할 때 applicationContextJobDataKey 값을 설정하게 되면 Spring Context 객체가 해당 이름으로 JobDataMap 에 추가되고 결과적으로 데이터베이스 Job Store 에 저장을 시도하면서 오류를 발생시키게 된다.
3. Quartz 설정
applicationContextSchedulerContextKey 값을 applicationContext로 지정하고 Job 구현 클래스에서 같은 이름으로 setApplicationContext 함수를 정의하면 자동으로 바인딩된다. 이를 통하여 Job 구현 클래스에서 Spring Context 에 접근이 가능하게 할 수 있다.
org.quartz.JobPersistenceException: Couldn't store job: JobDataMap values must be Strings when the 'useProperties' property is set. Key of offending value: applicationContext
그림3. 대기하는 Quartz Scheduler 인스턴스 로그 |
참고자료
- Quartz Scheduler Model
- Scheduling in Spring with Quartz
- Quartz Configuration Reference - Configure Clustering with JDBC-JobStore
- pass JobDataMap in the JobDetailFactoryBean not working
- Issue with Quartz persistent jobs while using with Spring
- One thought on “Configuring Quartz 2 with Spring in clustered mode”
댓글 없음:
댓글 쓰기