공부 흔적남기기

Spring Scheduler SchedLock MongoDB 설명 및 구현 본문

web study/Spring

Spring Scheduler SchedLock MongoDB 설명 및 구현

65살까지 코딩 2023. 12. 1. 20:33
728x90
반응형

 

문제 발생 

프로젝트에서 12시마다 특정 주기를 가진 아이템을 새로 생성해주는 스케쥴러가 있다.

서버를 k8s에  pod가 4개인 replica로 배포했는데 12시마다 4개의 아이템이 중복 생성되는 것을 확인.

 

해결 방법 구색

Shced Lock을 통해 하나의 작업에 대해 여러 스케줄러가 동시에 접근하지 못하도록 Lock을 걸 수 있음 

 

SchedLock이란 

스프링 스케줄러가 태스크를 시작하기전에 (아마 AOP 를 통해서겠지) DB에 요청을 보내 Lock이 걸렸는지 확인한다.

Lock이 걸렸다면 태스크를 Wait(기다리기)하지 않고 Drop(아에 실행 시키지 않음)한다.

Lock이 걸리지 않았다면 task를 수행한다.

SchedLock은 DB table 을 필요해 하는데 다음과 같다.

@Document(SchedLock.COLLECTION_NAME)
data class SchedLock(
	@Id
    val name: String,
    val lockUntil: LocalDateTime,
    val lockedAt: LocalDateTime,
    val lockedBy: String
) {
    companion object {
        const val COLLECTION_NAME = "schedLock"
    }
}

 

 ShcedLock이 Lock에 대한 조회를 할때 name을 사용하기 때문에 name은 unqiue해야한다. (name이 unique 하지 않다면 Lock에 대한 정보를 가져올 수 없겠지요?)

 ShcedLock은 Lock을 걸수 있는 최대시간과 적어도 Lock을 유지시켜주는 최소시간을 설정 할 수 있게해준다.

 최대시간은 Lock에 데드락이 걸리거나 stuck이 된 경우 Lock을 풀어준 역할을 하고\

 최소시간은 락이 최소시간안에 풀리지 않게 하는 역할을 한다.

 

 @EnableSchedulerLock

ShcedLock을 활성화시켜주는 Annotation으로 defaultLockAtMostFor(아까 말한 최대시간) 과 defaultLockAtLeastFor (최소시간)을 attribute로 가진다. 

예를들어 최대시간을 10초 최소시간을 1초로 잡는다면
@EnableSchedulerLock(defaultLockAtMostFor = "PT10S", defaultLockAtLeastFor = "PT1S") 다음과 같이 설정하면된다. 

 

 @SchedulerLock

 @SchedulerLock은 스케줄러 태스크 함수위에 명시하며 해당 스케줄러는 태스크를 실행시키기전에 Lock에 여부를 확인한다. 똑같이 lockAtMostFor (최대시간) 과 lockAtLeastFor (최소시간)을 attribute로 가지며 명시하지 않는다면 @ EnableSchedulerLock에서 설정한 default 값이 들어간다.

 

 

구현 코드

@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT10S", defaultLockAtLeastFor = "PT1S")
class SchedulerConfig(
    private val mongoTemplate: MongoTemplate
) {

    @Bean
    fun lockProvider(): LockProvider {
        val lockCollection = if (mongoTemplate.collectionExists(SchedLock::class.java)) {
            mongoTemplate.getCollection(SchedLock.COLLECTION_NAME)
        } else {
            mongoTemplate.createCollection(SchedLock::class.java)
        }
        return MongoLockProvider(lockCollection)
    }
}
@Scheduled(cron = "0 5 0 * * *", zone = "Asia/Seoul")
@SchedulerLock(name = "taskService_task")
fun task() {
    doSomething()
}

 

 

    implementation("net.javacrumbs.shedlock:shedlock-spring:4.44.0")
    implementation("net.javacrumbs.shedlock:shedlock-provider-mongo:4.44.0")

 

참조:

 https://bootcamptoprod.com/reliable-task-scheduling-with-shedlock/#using-shedlock-with-spring-scheduler-and-mongodb

 https://github.com/lukas-krecan/ShedLock

728x90
반응형