Develop/Spring+JPA

[Spring Batch] JobExecutionAlreadyRunningException 에러

연로그 2023. 10. 16. 21:25
반응형

 

🤯  에러 발생

Spring Batch에서 job을 실행하다가 아래와 같은 에러와 마주쳤다.

java.lang.IllegalStateException: Failed to execute ApplicationRunner
...
Caused by: org.springframework.batch.core.repository.JobExecutionAlreadyRunningExceptionA job execution for this job is already running: JobExecution: id=4223, version=1, startTime=2023-08-21 19:14:19.0, endTime=2023-08-22 15:38:48.0, lastUpdated=2023-08-21 19:14:19.0, status=FAILED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=4210, version=0, Job=[memberStatusUpdateJob]], jobParameters=[{}]

 

 

🙄 에러 원인

위 에러는 job 실행 중에 애플리케이션을 강제로 종료시키고, 다시 실행한 경우에 발생했다. 에러로그를 통해 추측해보자면 내가 강제로 애플리케이션을 강제로 종료했기 때문에 해당 job이 비정상적으로 종료되었지만, Spring Batch는 해당 job이 아직 실행중이라고 판단하는 모양이다.

 

Spring Batch에서 Job을 실행시키기 위해서는 JobLauncher interface의 구현체가 필요하다. 기본적으로는 SimpleJobLauncher를 사용하고 있으니 해당 클래스로 코드 까기 해보겠다. (Spring Batch 5.0.0부터는 deprecated 되고 TaskExecutorJobLauncher 클래스로 대체되었다.)

 

SimpleJobLauncher의 run 메서드를 보면 한 가지 눈에 띄는 점이 있다. JobRepository를 통해 JobExecution의 조회하거나, 생성, 수정하는 로직이 눈에 보인다. 이는 Spring Batch가 Job을 실행시킬 때 BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION 등 여러 테이블에 메타데이터를 기록하기 때문이다. (Spring Batch docs 참고)

@Override
public JobExecution run(final Job job, final JobParameters jobParameters)
        throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
        JobParametersInvalidException {

    // ...
    JobExecution lastExecution = jobRepository.getLastJobExecution(job.getName(), jobParameters);
    
    // ...
    jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);

    // ...
    jobRepository.update(jobExecution);
    
    // ...
}

 

 

또한 run 메서드에서 'A job execution for this job is already running'라는 에러 로그가 발생하는 포인트를 찾을 수 있다. 아래와 같이 status가 running이면 예외를 발생시키는 코드를 확인할 수 있다. 

@Override
public JobExecution run(final Job job, final JobParameters jobParameters)
        throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
        JobParametersInvalidException {
    // ...
    for (StepExecution execution : lastExecution.getStepExecutions()) {
        BatchStatus status = execution.getStatus();
        if (status.isRunning() || status == BatchStatus.STOPPING) {
            throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: " + lastExecution);
        } else if (status == BatchStatus.UNKNOWN) {
            throw new JobRestartException("...");
        }
    }
    // ...
}
public enum BatchStatus {
    public boolean isRunning() {
        return this == STARTING || this == STARTED;
    }
    ...
}

 

 

🧐 해결 방법

아래 쿼리를 수행하여 status를 변경해주면 된다. ${id}에는 에러로그를 참고하여 JobExecution의 id로 수정하면 된다. (위 에러로그의 경우, 4223)

UPDATE
    BATCH_JOB_EXECUTION
SET END_TIME  = now(),
    STATUS    = 'FAILED',
    EXIT_CODE = 'FAILED'
WHERE JOB_EXECUTION_ID = ${id}
;
 
UPDATE
    BATCH_STEP_EXECUTION
SET END_TIME  = now(),
    STATUS    = 'FAILED',
    EXIT_CODE = 'FAILED'
WHERE JOB_EXECUTION_ID = ${id}
;

 


도움 및 참고

 

반응형