Camel에서 스케줄링이 필요한 이유
배치 처리, 정기 리포트 생성, 주기적인 데이터 동기화 등 시간 기반 작업은 모든 기업 시스템에 존재합니다. Camel은 Timer와 Quartz라는 두 가지 스케줄링 컴포넌트를 제공합니다.
Timer 컴포넌트 – 단순 주기 실행
일정 간격으로 반복 실행할 때는 Timer 컴포넌트가 가장 간단합니다.
// 5초마다 실행
from("timer:cleanup?period=5000")
.log("정리 작업 실행")
.to("bean:cleanupService");
// 10초 후 단 한 번만 실행
from("timer:init?delay=10000&repeatCount=1")
.to("bean:initService");
Timer는 단순하지만 복잡한 크론 스케줄은 표현하기 어렵습니다. 예를 들어 “평일 오전 9시에만 실행”같은 조건은 Quartz가 필요합니다.
Quartz 컴포넌트 – 크론 기반 스케줄링
Quartz는 기업용 스케줄러로, 크론 표현식을 지원합니다. camel-quartz2 의존성을 추가하면 사용할 수 있습니다.
// 매일 오전 9시에 실행 (크론: 초 분 시 일 월 요일)
from("quartz2:daily-report?cron=0+0+9+*+*+?")
.to("bean:reportService?method=generateDaily");
// 평일(월-금) 오전 8시 30분에 실행
from("quartz2:weekday-sync?cron=0+30+8+?+*+MON-FRI")
.to("direct:syncData");
Quartz는 내부적으로 데이터베이스에 스케줄 상태를 저장할 수 있어서, 서버 재시작 후에도 놓친 실행을 보완(misfire) 처리할 수 있습니다.
실전 배치 처리 패턴
실제 배치 시스템에서 자주 사용하는 패턴을 살펴보겠습니다.
- 스케줄 → DB 조회 → 처리 → 결과 저장: 가장 일반적인 ETL 패턴
- 스케줄 → 파일 폴링 → 처리 → 아카이브: 파일 기반 배치
- 스케줄 → API 호출 → 데이터 집계 → 알림: 외부 데이터 수집
from("quartz2:etl?cron=0+0+2+*+*+?") // 새벽 2시
.to("sql:SELECT * FROM staging_orders WHERE processed=0")
.split(body())
.to("bean:orderProcessor")
.to("sql:UPDATE staging_orders SET processed=1 WHERE id=:#id")
.end()
.log("배치 완료");
중복 실행 방지 – Idempotent Consumer
클러스터 환경에서 여러 서버가 동시에 배치를 실행하면 중복 처리가 발생할 수 있습니다. Quartz의 클러스터링 기능이나 Camel의 Idempotent Consumer EIP를 함께 사용하면 이 문제를 해결할 수 있습니다.
from("quartz2:clustered-batch?cron=0+0+1+*+*+?")
.idempotentConsumer(header("jobId"),
JdbcMessageIdRepository.jpaMessageIdRepository(entityManager, "batch"))
.to("bean:batchService");