afterStep 에서 Exception을 던져도 다음 Step이 이어서 실행된다.
afterStep에서 검증 로직 돌린 후, 다음 Step 실행하지 않고 배치를 종료하고 싶은 경우가 있다. 배치 애플리케이션을 아예 종료해버리는 방법도 있지만, 보다 graceful 하게 처리하고 싶은 경우, 다음 Step이 실행되지 않도록 하려면?
종료 상태를 나타내는 Status는 BatchStatus와 ExitStatus 두개가 있다.
- https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#batchStatusVsExitStatus
ExitStatus represents the status of a Step after it finishes execution.
- on(ExitStatus…) 로 Step의 종료 상태에 따른 분기 처리를 위해 사용한다.
- BatchStatus is an enumeration that is a property of both JobExecution and StepExecution and is used by the framework to record the status of a Job or Step.
- Job과 Step의 전반적인 상태를 관리하기 위해 사용한다. ( 더 큰 범위 )
어떤 Step에서 문제가 발생했을 때, 다음 Step이 실행되지 않도록 하는 방법은 2가지가 있다.
1. 비정상 ExitStatus를 반환하고 on() 으로 분기해주는 방법
1
2
3
4
return jobBuilderFactory.get(jobName)
.start(step1)
.on(ExitStatus.FAILED.getExitCode()).end()
...
2. BatchStatus가 COMPLETED가 아니도록 하는 방법
1
2
3
4
5
6
7
8
9
10
11
// BatchStatus가 COMPLETED가 아니면 다음 step을 실행하지 않는다
class SimpleJob {
protected void doExecute(JobExecution execution) throws JobInterruptedException, JobRestartException, StartLimitExceededException {
while(steps.hasNext()) {
Step step = (Step)steps.next();
stepExecution = this.handleStep(step, execution);
if (stepExecution.getStatus() != BatchStatus.COMPLETED) {
break;
}
}
...
기본적으로 일일히 on()을 이용해 비정상 ExitCode에 대해 분기처리 해주지 않아도, 예외가 발생하면 BatchStatus가 비정상으로 세팅되어 다음 Step 실행이 되지 않게끔 되어 있다.
beforeStep, tasklet에서 발생한 Exception에 대해서는 그렇다. 하지만, afterStep에서 Exception이 발생하는 경우에는 다르다.
afterStep에서의 Exception은 배치를 종료시키지 않는다.
AbstractStep::execute
부분 확인해보면, [beforeStep, Tasklet]에서 Exception 던지는 경우 BatchStatus.FAILED로 변경하기 때문에 배치가 종료된다. 하지만 [afterStep]에서 Exception throw 하는 경우 로그만 찍고 넘어가버려 다음 Step이 실행된다.
afterStep에서의
setTerminateOnly는 배치를 종료시키지 않는다. AbstractStep::execute
부분 확인해보면, [beforeStep, Tasklet]에서 setTerminateOnly 하는 경우 BatchStatus.STOPPED로 변경하기 때문에 배치가 종료된다. 하지만 [afterStep]에서 setTerminateOnly 하는 경우 동작에 아무런 차이가 없다. afterStep 호출 후 isTerminateOnly 체크 하지 않는다. 그냥 다음 Step이 실행된다.
참고) afterStep 실행부는 finally block에 있기 때문에 beforeStep, tasklet에서 Exception이 일어나도 항상 실행된다.
afterStep에서 직접 BatchStatus를 변경하면, on 분기를 사용하지 않아도 다음 Step 실행을 막을 수 있다.
afterStep에서 검증 로직 돌린 후, 다음 Step 실행하지 않고 배치를 종료하고 싶다면? (on 분기를 사용하지 않으면서) BatchStatus를 STOPPED | FAILED 로 세팅하면 된다.
1
2
3
4
5
override fun afterStep(stepExecution: StepExecution): ExitStatus {
stepExecution.upgradeStatus(BatchStatus.STOPPED)
stepExecution.exitStatus = ExitStatus.STOPPED
return stepExecution.exitStatus
}