[Quartz] Spring Batch Re-Schedule When Fail (JDBC)

S_H_H·2022년 10월 12일
0

Quartz And Batch

목록 보기
6/8

이전 글에서 XML(In memeory) 설정 환경에서 Restart에 대해 다룬적 있다
이번에는 JDBC 환경에서 Restart했던 작업을 적어볼까한다.

Quartz의 실행 정보과 Batch의 실행 이력들이 전부다 DB 조회가 가능한 시점에서 
최대한 DB에 대한 정보를 활용하고 싶었기에 이렇게 만들어 진 듯?

재 실행을 위한 Build Up

JOB 실패에 대한 판단

Job은 실행되고, 종료가 된다.
그렇다면 Job이 종료된 시점에서, 언제 어떠한 방법으로 실패가 되었는지 알아차릴 수 있을까?

  • Batch_ 테이블 조회
    BATCH_JOB_EXECUTIONBATCH_STEP_EXECUTION 테이블을 조회 하면 시작, 종료 시간 및 종료된 상태, 에러 내용도 확인할 수 있다.

  • JobListenerSupport 사용
    jobWasExecuted 를 사용하면 Job이 종료된 이후에 호출되기 때문에 메타 테이블을 조회가 가능하다


JOB DATA

보통 Listener는 공통으로 공유를 하고, 스케줄러를 통해 실행되는 Job이 한두 개가 아닌데 동일한 Error로 재 시작하면 안될 것 같은데.....

  • QRTZ_JOB_DETAILS 사용
    JOB_DATA를 통해 key, value를 통해 값 기입
    key: RESTART, value: 재 시작 기간

  • JobParameter 이용

    JobParameters params = new JobParametersBuilder()
            .addString("JobData", JobData)
            .toJobParameters();
    
    jobLauncher.run(job, params);

    JobParameter에 값을 넣어놓을 경우 각 Context의 정보로 접근이 가능하다.


StepExecution - ExitStatus

Job 또는 Step이 실행 중에 Error가 발생하면 모두 재 시작을 해야할까?
Exception은 다양한 이유로 발생할 수 있다. 특정한 원인일 때만 재 시작을 하고 싶었다.

  • StepExecutionListenerSupport
    afterStep을 통해 종료된 Step에서 getFailureExceptions를 통해 처리

afterStepExitStatus를 반환을 합니다.
재 시작이 필요한 Exception에 대해서는 RESTART로 처리해 DB 조회 시 구분을 쉽게 했습니다.

public static final String STEP_EXITSTATUS_RESTART = "RESTART";
-- 생락 --
public ExitStatus afterStep(StepExecution stepExecution) {
	if(stepExecution.getFailureExceptions() 에러 분기 처리){
    	return new ExitStatus(STEP_EXITSTATUS_RESTART);
    }
    return stepExecution.getExitStatus();
}

저는 이부분에서 JOB_DATA에 RESTART 값이 있는지 분기 처리도 추가 했습니다.


Re-ScheduleJob

재시작 주기에 대해서는 JOB_DATA에 저장된 정보를 가져오고
Context정보에 있는 JOB 실행 시간으로 만들어보자

TriggerBuilder를 통해 제작 후, Scheduler에 등록을 하면 QRTZ_TRIGGERS 테이블에 등록된걸 확인할 수 있다.

String restartDateTime = jobExecutionContext
									.getFireTime()
                                    .toInstant()
									.atZone(ZoneId.of("Asia/Seoul"))
									.toLocalDateTime()
                                    .plusSeconds(JOB_DATA의 value값 기입)
									.format(DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy"));

Trigger trigger = TriggerBuilder
						.newTrigger()
						.forJob(jobName)
						.withIdentity(jobID, 'restart')
						.withSchedule(cronSchedule(restartDateTime))
						.build();

jobExecutionContext.getScheduler().scheduleJob(trigger);

결론

  1. JOB_DATA에 재실행 value 기입
  2. Step 종료 후, 실패 시 EXIT_CODE 변경
  3. Job 종료 이후 메타 테이블 조회로 실패한 Step이 있는지 조회
  4. Trigger 등록

추가 작업

Job 종료 후 DB조회 할려고 할때 Context 정보에는 PK 값이 없다

  • Job 실행 시 Jobparam 데이터에 임의의 PK 값을 넣어서 해결
  • 실제 DB에 들어가는 PK값을 가져올려고 SimpleJobLauncher 구현을 할려 했지만 한두개를 만들어야할 사항이 아니여서 포기

재실행 횟수에 대한 제한이 없음으로 이건 필요시 작업이 필요함

동일한 방법으로 Batch가 실패한 경우 Listener에서 확인 후 알림 기능도 추가 했음


시행착오

  • jobWasExecuted 파라미터에 JobExecutionException 을 활용해 볼려고 했지만 실패
  • 당시에 Bean에 대한 개념이 없어서 NULL에러 고생함
  • docs.spring.io에서 쫌 찾아보고 했으면 좋았을껄.....
지금 문서를 찾아보면 좋은 기능이 많이 나온듯
내 입맛대로 커스텀 한 덕분에 여러 기능을 더 쓸수있어서 난 좋았다

profile
LEVEL UP

0개의 댓글