Open jowoohyeong opened 1 year ago
위와 같이 2개 이상의 서버로 구성된 환경에서 중복된 Schedule이 실행되지 않도록 Lock을 걸 수 있게 만들어놓은 라이브러리이다. maven repository에 shedlock이라는 이름으로 올라와있다. 그중에 shedlock-spring과 shedlock-provider-jdbc-template을 추가한다.
shedlock-provider-jdbc-template을 추가하는 것을 보면 데이터베이스를 이용하는 것을 예상할 수 있다. RDB 말고도 maven repository 검색결과 목록에 MongoDB, Redis provider도 보이는 것을 보면 다른 저장소를 통해서도 가능한 걸로 보인다. maven repository shedlock 검색결과 페이지
<!-- Scheduler lock -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>3.0.0</version>
</dependency>
<!-- JDBC Template -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>3.0.0</version>
</dependency>
public class ScheduleController {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
<bean id="lockProvider" class="net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider">
<constructor-arg ref="dataSource"/>
</bean>
Bean 등록 방법: java or xml 선택 만약 기존에 연동된 jdbc 또는 DB Connector가 없는 경우 DB연동부터 설정해줘야 한다. 여기서 ref="dataSource"는 기존에 연결되어있는 dataSource 명을 넣어주면 된다.
Schedule Lock을 사용하기 위해 위에서 설정한 dataSource에 해당하는 DB에 테이블 생성, 이를 통해 lock기능 사용 가능
DROP TABLE IF EXISTS `shedlock` RESTRICT;
CREATE TABLE `shedlock` (
`name` VARCHAR(64) NOT NULL COMMENT '스케줄잠금이름', -- 스케줄잠금이름
`lock_until` TIMESTAMP(3) NULL COMMENT '잠금기간', -- 잠금기간
`locked_at` TIMESTAMP(3) NULL COMMENT '잠금일시', -- 잠금일시
`locked_by` VARCHAR(255) NULL COMMENT '잠금신청자' -- 잠금신청자
)
COMMENT '스케줄잠금';
ALTER TABLE `shedlock` ADD CONSTRAINT `PK_shedlock` -- 스케줄잠금 기본키
PRIMARY KEY (
`name` -- 스케줄잠금이름
);
여기서 name은 어노테이션에서 전달할 이름이다. 고유값으로 들어가고 이름으로 스케줄을 구분한다.
어노테이션을 사용해서 lock을 걸어준다.
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S") // Scheduler Lock 사용 가능 설정 (기본 30초동안 Lock)
public class BatchController {
private static final String ONE_MIN = "PT1M"; // 1분동안 LOCK
@Scheduled(cron = "0 10 * * * ?") // 초(0~59) 분(0~59) 시(0~23) 일(1~31) 월(1~12) 요일(1~7, 일요일 : 1) 연도(생략가능)
// Schdule Lock (1분동안)
@SchedulerLock(name = "runScenarioOneTime", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN)
public void runScenarioOneTime() throws Exception {
// do something...
}
@Scheduled(cron = "0 20 * * * ?")
// Schdule Lock (1분동안)
@SchedulerLock(name = "runScenarioCycle", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN)
public void runScenarioCycle() throws Exception {
// do something...
}
}
이렇게 간단한 어노테이션 설정을 통해서 각 WAS가 Scheduling할 때 생성한 테이블을 참조하여 아래와 같은 작업이 이루어진다.
Spring의 @Scheduled 어노테이션은 Spring Framework에서 쉽게 cron을 구성할 수 있는 유용한 기능이다.
그런데 WAS를 늘리게 되면 상당히 골치 아픈 상황이 벌어진다.
cron작업이 WAS마다 실행되기 때문에 WAS의 개수만큼 중복된 cron이 실행되기 때문이다.
이러한 방법을 정리해보려 한다.