[DEV] J-Jay

Quartz Scheduler 배치 PUSH 중복 발송 본문

Trouble Shooting

Quartz Scheduler 배치 PUSH 중복 발송

J-Jay 2023. 8. 14. 22:52
728x90

첫번째 문제

일시: 2023.08.03 16:30

PUSH 중복 발송 (동일한 내용)

이전까지 잘 동작하던 Quartz 로 만든 스케줄러가 이상하게 동작했다.

 

추측

스케줄러의 로그를 분석한 결과 배치의 작업명을 변경해서 생긴 문제였다. 

ex) 작업명: 배치1 → 배치2 변경

동일한 시간에 이전 작업명 배치1과 배치2가 동시에  실행이 된거로 추측된다.

 

해결 및 보류

작업명을 배치2 배치1로 원복했다. 

원복하고 난 후 딱히 문제가 발생하지 않아 보류...

 

또 다시 문제 발생...

다음날 09:00에 동일한 문제가 또 발생 했다. (PUSH 중복 발송)

왜지? 작업명은 원복했는데....?

로그를 보니 또 동일한 시간대에 어제와 마찬가지로 작업명이  배치1(기존) 배치2(변경) 가 동시에 실행 됐다.

분명 어제 작업명을 원복했는데? 귀신 인가...?

 

원인

개발서버에서 동일한 조건으로 어제와 같이 배치의 작업명 변경 후, 다시 원복을 해보았다.

결과적으로 어제 추측한 내용이 맞았다.

스케줄러의 로그가 동일한 시간에 이전 작업명 배치1과 배치2가 동시에  실행이 됐다.

 

Q: 왜지?

A: 메모리 때문이야.

 

해결

Quartz Scheduler로 작성한 배치의 작업명은 key값이며 해당 Scheduler는 메모리 상에 올라가 있는 것으로 확인했다.

즉, 서버 재기동 또는 메모리에 올라간 값들을 갱신 해주지 않으면 배치1(기존)  배치2(변경) 가 2번 실행이 되는 것이다.

 

일단 당장에 해결을 위해 서버 재기동을 먼저하고 Code를 분석했다.

 

문제가 된 코드

public void reload() {

...

  //DB에 있는 스케줄러(배치) 조회 → 삭제 → 등록
  List<SchedulerJob> jobs = schedulerDao.selectListSchedulerJob(params);
  for(SchedulerJob job : jobs) {
  	looger.info("[SSCHEDULER] : {}" , job);
    deleteInsertSchedulerJob(job);
  }

}

DB에 등록된 Scheduler만 조회해서 삭제후에 다시 등록 처리한다.

즉 DB에 등록되지 않은(메모리에만 올라간) Scheduler는 처리를 하지 않는다.

 

수정 코드

public void reload() {

...

  //메모리상에 있는 scheduler 모두 삭제
  Set<JobKey> schJobKeys = scheduler.getJobKeys(GroupMatcher.anyJobGroup()); //jobkeys(작업명들)
  scheduler.deleteJobs(schJobKeys.stream().collect(Collectors.toList()); //scheduler 삭제

  //DB에 있는 스케줄러(배치) 조회 → 삭제 → 등록
  List<SchedulerJob> jobs = schedulerDao.selectListSchedulerJob(params);
  for(SchedulerJob job : jobs) {
  	looger.info("[SSCHEDULER] : {}" , job);
    deleteInsertSchedulerJob(job);
  }

}

메모리상에 있는 scheduler를 모두 삭제 후 DB에 있는 내용들로만 처리하도록 로직을 추가 했다.

 

고생했다.

끝.