일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- java 팩토리얼 개수
- Spring ipfs
- mongodb lookup
- go
- spring mongoTemplate switch
- 백준 특정한 최단 경로
- 자바 백준 팩토리얼 개수
- 백준 연결요소 자바
- spring mongoTemplate
- rabbitmq 싱글톤
- java 파티
- java 1238
- 백준 1504 java
- javav 1676
- ipfs bean
- nodejs rabbitmq
- spring mongodb
- 안정해시
- java 1509
- 자바 1676
- java 백준 1509
- kotiln functional interface
- kotiln const val
- 백준 2252 줄세우기
- 전략 패턴이란
- 익명 객체 @transactional
- spring mongodb switch
- ipfs singletone
- kotiln const
- Java Call By Refernce
- Today
- Total
공부 흔적남기기
Spring Scheduler SchedLock MongoDB 설명 및 구현 본문
문제 발생
프로젝트에서 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")
참조: