threshold
일단 위 단어를 찾으면 제일 먼저 나오는 뜻은 ‘문지방’이지만 프로그램에서 사용하는 의미는 임계치, 시작점 정도로 이해하면 될 듯 하다.
발단
SpringBoot + Quartz 로 배치관련 어플리케이션을 개발중에 스케쥴링 된 트리거를 정지(pause) 후 재개(resume)하는 기능을 개발하고 있었다. (Trigger는 Job이 실행될 시점이라고 이해하자.)
등록된 Trigger는 Quartz의 Scheduler 인터페이스 구현체에 의해 제어될수 있는데 다음과 같은 호출로 정지/재개한다.
서비스 클래스 코드의 일부이다. 생성된 스케쥴러 빈을 주입받아 TriggerKey를 인자로 등록된 Trigger를 제어한다.
@Autowired
Scheduler scheduler;
public void pause(TriggerKey triggerkey) throws SchedulerException {
scheduler.pauseTrigger(triggerkey);
}
public void resume(TriggerKey triggerkey) throws SchedulerException {
scheduler.resumeTrigger(triggerkey);
}
문제는 pause 후 몇 초가 지나고 resume을 해보면 이미 Trigger에 세팅된 시작시점이 지난 Trigger가 resume과 함께 시작해버린다. (실행 되어야 하나 실행하지 못하는 것은 misfire라 하며, Trigger에 misfire 정책을 MISFIRE_INSTRUCTION_DO_NOTHING 으로 했음에도 발생)
예를들어 매분 10초마다 실행되는 Trigger-Job이 있다고 하면,
- 0초에 해당 배치를 pause → 10초에 pause 상태이므로 실행 안됨 → 20초에 resume → 다음 분 10초에 실행
이런 동작을 기대했지만 실제로는 아래와 같이 되어버린다.
- 0초에 해당 배치를 pause → 10초에 pause 상태이므로 실행 안됨 → 20초에 resume과 함께 10초에 실행되어야 할 Trigger-Job이 실행 → 다음 분 10초에 실행
해결
Quartz에서는 misfireThreshold 값이 존재하고 디폴트가 60초로 세팅된다.
Trigger가 재개될 때는 두 가지 스탭으로 실행여부를 결정하는 것 같다.
- nextFireTime(다음 실행시간)이 (현재시간 - misfireThreshold) 크면 실행한다. 작다면 2번에 따른다.
- Trigger에 설정된 misfire 정책에 따라 실행한다.(MISFIRE_INSTRUCTION_DO_NOTHING이면 실행 안함)
즉, 나는 misfireThreshold가 60초 디폴트 설정 된 상태에서 60초가 지나기 전에 pause를 풀었으므로 misfire정책에 상관없이 즉시 실행이 되었던 것이다.
그래서 해결법은 misfireThreshold 를 짧게 설정 하던지, pause 후에 60초가 지나서 resume을 하면 된다.
misfireThreshold는 properties 설정으로 다음과 같이 설정할 수 있다.
quartz: properties: org.quartz.jobStore.misfireThreshold: 10000 ## misfire라고 판단하는 기준시간 |
'개발 > 기타' 카테고리의 다른 글
웹 템플릿 엔진(Web Template Engine) (0) | 2020.12.08 |
---|---|
인텔리제이 어플리케이션 외부 옵션 및 변수 (0) | 2020.12.07 |
패스워드 암호화에 대해서 (0) | 2020.12.06 |
LastModified 헤더를 이용한 파일변경 체크 (0) | 2020.12.06 |
Maven 기본 (0) | 2019.11.12 |