귀찮지만 만들어보자

이미 실행중인 job이 있을때 어떻게 할까? 본문

스프링 배치(Spring Batch)

이미 실행중인 job이 있을때 어떻게 할까?

타우렌주술사 2020. 4. 17. 13:12

스프링 배치를 제대로 개발해본 경험이 없어서 이런 경우에 어떻게 할지 난감했습니다

 

실행 주기가 5분인 배치에서 이전에 실행했던 배치가 아직 끝나지 않았는데 
다음 배치가 시작되면 어떻게 할까?

 

처음에 이런 상황에서 어떻게 대처할지 생각하다가 떠올랐던건 상태 플래그를 두고 관리하는 방법이었습니다

아래와 같이 thread-safe한 set 을 만들고 job의 중복 여부를 set으로 관리하는 방법이었는데...

썩 좋아보이는 코드는 아니어서 조금 더 찾아봤습니다

 @Bean
 fun rewardJobListener(): JobExecutionListener {
    return object : JobExecutionListener {
        val RUNNING_JOBS: Set<String> = Collections.synchronizedSet(HashSet<String>())

        override fun beforeJob(jobExecution: JobExecution) {
            val jobName = jobExecution.jobInstance.jobName
            logger.info("reward job starting")
            if (RUNNING_JOBS.contains(jobName)) {
                logger.info("$jobName is already execute")
                jobExecution.stop()
            } else {
                RUNNING_JOBS.plus(jobName)
            }
        }

        override fun afterJob(jobExecution: JobExecution) {
            val jobName = jobExecution.jobInstance.jobName
            if (jobExecution.status == BatchStatus.COMPLETED) {
                logger.info("$jobName is complete")
            } else if (jobExecution.status == BatchStatus.FAILED) {
                logger.error("$jobName is failed. ${jobExecution.allFailureExceptions}")
            }
            RUNNING_JOBS.minus(jobName)
        }
    }
}

 

더 찾아보니 훨씬 더 깔끔한 방법이 있어서 이런식으로 구현했습니다

디버깅을 해보면 리스너로 들어오는 시점에 새로운 job이 실행되는 것을 알 수 있고,

기존에 실행된 job이 끝나지 않았다면 set의 size는 1이상이 됩니다

@Component
class PreventDuplicationJobListener(
        private val jobExplorer: JobExplorer
) : JobExecutionListener {

    override fun beforeJob(jobExecution: JobExecution) {
        val jobExecutionSet = jobExplorer.findRunningJobExecutions(jobExecution.jobInstance.jobName)
        if (jobExecutionSet.size > 1) {
            jobExecution.stop()
        }
    }

    override fun afterJob(jobExecution: JobExecution) {
    }
}

 

-끝-