Spring batch step flow
Controlling Step Flow
- 하나의 스텝에서 다른 스텝으로 이동할 때, 흐름을 제어하는 방법
- 스텝의 실패가 반드시 Job의 실패를 의미하지 않는다
- 스텝의 성공의 의미에 추가적인 여러 의미를 부여할 수 있음
- 스텝의 구성에 따라서, 어떤 스텝은 전혀 실행되지 않을 수 있음
연속 흐름(Sequential flow)
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(stepA())
.next(stepB())
.next(stepC())
.build();
}
- 일반적으로 가장 많이 쓰는 형태
- stepA, stepB, stepC가 순차적으로 발생
- stepA가 실패하면, 전체 잡은 실패가 되고, stepB를 실행하지 않는다.
조건부 흐름(Conditional flow)
- 위의 연속적 흐름에서 두 가지 결론이 있다.
- 이전 스텝이 성공하면, 다음 스텝은 반드시 실행된다.
- 이전 스텝이 실패하면, 잡도 실패해야 한다
- 많은 경우에, 이것은 충분하지만 실패를 처리하기 위한 다양한 스텝을 만들 수 있다.
- StepA가 성공하면, StepB
- StepA가 실패하면, StepC
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(stepA())
.on("*").to(stepB())
.from(stepA()).on("FAILED").to(stepC())
.end()
.build();
}
- on(“*“)은 ExitStatus를 매칭하기 위한 method
- “*” : 모든 문자(Regular expression)
- 만약에 on() 에서 다룰 수 없는, ExitStatus가 발생하면 프레임워크는 예외를 던지고, 잡을 실패시킨다.
- on의 적용 방식은, 가장 상세화되어 있는게 우선이다.
- “*“가 있다고 하더라도, “FAILED”가 상세화되어 있으므로, “FAILED”가 발생하면 “FAILED” 상태
Batch Status Vs Exit Status
- 조건부 흐름에서는, BatchStatus와 ExitStatus를 이해하는게 가장 중요
- BatchStatus는 JobExecution과 StepExecution을 모두 사용할 수 있는 enumeration
- BatchStatus : COMPLETED, STARTING, STARTED, STOPPING, STOPPED, FAILED, ABANDONED, or UNKNOWN
...
.from(stepA()).on("FAILED").to(stepB())
...
- “FAILED”는 BatchStatus가 아니라, 스텝 실행이 끝나고 상태를 표시하는 ExitStatus이다.
- 일반적으로는 BatchStatus = ExitStatus이지만, 하지만
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(step1()).on("FAILED").end()
.from(step1()).on("COMPLETED WITH SKIPS").to(errorPrint1())
.from(step1()).on("*").to(step2())
.end()
.build();
}
- on은 Enumeration(Batch Status)이 아닌 ExitStatus이므로 원하는대로 상태를 표기할 수 있음
public class SkipCheckingListener extends StepExecutionListenerSupport {
public ExitStatus afterStep(StepExecution stepExecution) {
String exitCode = stepExecution.getExitStatus().getExitCode();
if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) &&
stepExecution.getSkipCount() > 0) {
return new ExitStatus("COMPLETED WITH SKIPS");
}
else {
return null;
}
}
}
- SkipCheckingListener를 통해서, 특정 상태에 따라서 ExitStatus를 다르게 줄 수 있음
- BatchStatus는 Enumeration이기 때문에, COMPLETED만 표현 가능한 한계를 ExitStatus로 극복
중지 구성
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(step1())
.build();
}
- 스텝만 실행시키고 어떠한 transitions도 없는 경우
- 스텝이 만약에 ExitStatus가 FAILED라면, Job의 ExitStatus, BatchStatus 모두 FAILED
- ExitStatus가 COMPLETED이라면, Job의 ExitStatus, BatchStatus도 COMPLETED
- 중지된 스텝은, 잡의 어떤 스텝들의 BatchStatus나 ExitStatus에 영향을 주지 않음
- 중지된 스텝은 오직 Job의 마지막 상태에만 영향을 준다
스텝에서 종료시키기
- 잡이 BatchStatus가 COMPLETED 상태가 된다면, 다시 재실행할 수 없다
- end() 메소드는 이러한 역할을 하는데 도와준다.
- end() 메소드의 파라미터에 어떠한 값도 정의하지 않는다면, COMPLETED가 default로 들어감
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(step1())
.next(step2())
.on("FAILED").end()
.from(step2()).on("*").to(step3())
.end()
.build();
}
- step2가 실패하면
- Job 중지
- BatchStatus와 ExitStatus는 COMPLETED 상태가 되므로 재실행 불가
스텝 실패시키기
- 스텝을 실패시키면, Job은 BatchStatus가 FAILED 되고 재시작은 할 수 있음
- step2가 실패하고, BatchStatus는 FAILED를 가지면 step3은 실행할 수 없음
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(step1())
.next(step2()).on("FAILED").fail()
.from(step2()).on("*").to(step3())
.end()
.build();
}
주어진 스텝에서 잡을 중지시키기
- 특정 스텝에서 잡을 중지시킨다는건, 잡의 BatchStatus가 STOPPED가 되는걸 의미
- 잡을 중지시키는건, 일시적으로 처리를 멈추고 잡을 재수행하기전에 어떠한 작업을 수행할 수 있음
- step1이 COMPLETED이 되면, Job을 COMPLETE 상태로 종료시키고, 해당 잡을 재수행시에, step2부터 실행
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
.start(step1()).on("COMPLETED").stopAndRestart(step2())
.end()
.build();
}