본문 바로가기

Langauge/Spring framework

[Spring framework] 멀티서버 스프링 스케줄러 처리를 위한 ShedLock

Spring famework 사용 시 멀티서버 즉, 2개 이상의 서버로 구성된 환경에서

스프링 스케줄러를 사용하게 되면 중복된 cron 이 실행된다.

 

이는 cron 작업이 was마다 실행되기 때문에 발생하는 문제로

was 개수만큼 중복된 cron 이 실행되어 한 번만 실행되는 것이 아닌 두번 이상 실행이 되는 것이다.

 

서버를 삭제 후 재 생성하기도 했지만 결국 스프링 스케줄러 중복실행 문제는 해결하지 못했고,

2개 이상의 서버에서 중복실행을 막기위해서 Lock기능을 이용하여 DB를 공통참조하도록 제공하는

라이브러리(Lock API)인 ShedLock 를 통해 해결할 수 있었다.

 

처리방식은 ShedLock 테이블에 동일한 데이터가 있는지 여부를 파악한 후,

만약 동일한 이름의 데이터가 있다면 Scheduling 을 중단하고

동일한 데이터가 없다면 ShedLock 테이블에 이름, 잠금일시, 기간 등을 설정하여 insert 해준다.

 

 

 

처리방법은 다음과 같다.

 

1. Oracle DB

Lock 기능을 사용하기 위해서 DB 에 테이블을 생성한다.

create table SHEDLOCK (
name varchar (64),
LOCK_UNTIL timestamp (3) null ,
LOCKED_AT timestamp (3) null ,
LOCKED_BY varchar (255),
primary key (name)
);

 

2.  pom.xml  

pom.xml 에 라이브러리를 추가한다.

<!-- === 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>

 

3.  root-context.xml

myBatis(JDBC)설정한 곳 아래에 Bean 을 등록해준다.

※ Controller 에서 @Bean 을 등록해주어도 된다.

<bean id="lockProvider" class="net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider">
	<constructor-arg ref="dataSource"/>
</bean>

 

4.  Service 단

본인은 Controller 에서는 특정 URL 사이트로 연결하도록 잡아주기만 하고,

Service 단에서는 cron 작업(특정날짜 및 시각 설정)을 해주었다.

따라서 Service 단에서 클래스와 메소드에 아래와 같이 어노테이션을 추가해준다.

 

@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")

private static final String ONE_MIN = "PT1M";  // 1분동안 LOCK
@SchedulerLock(name = "고유한 이름 지정", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN)

 

@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S") // Scheduler Lock 사용 가능 설정 (기본 30초동안 Lock)
@Service
public class ScheduleService implements InterScheduleService {

    private static final String ONE_MIN = "PT1M"; // 1분동안 Lock

    @Scheduled(cron="0 30 4 1 1 *") // 매년 1월 1일 4시 30분
    @SchedulerLock(name = "runWorkTime", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN)
	public void  getWorking() throws Exception {
    
        //do something....
        
    }

 

 

 

 

 

※ 이 글은 아래의 블로그 글을 참고하였습니다.

https://steady-snail.tistory.com/174

https://laba.tistory.com/14