-
스프링 배치 도메인 이해 -StepExecutionStudy/Spring Batch 2024. 2. 15. 07:49
StepExecution
1) 기본 개념
- Step에 대한 한 번의 시도를 의미하는 객체로 Step 실행 중에 발생한 정보들을 저장하고 있는 객체.
- 시작시간, 종료시간, 상태(시작됨/완료/실패), commit count, rollback count 등의 속성을 가진다.
- Step이 매번 시도될 때마다 각 Step별로 생성된다.
- Job이 재시작하더라도 이미 성공적으로 완료된 Step은 재실행되지않고 실패한 Step만 실행된다.
- 이전 단계의 Step이 실패해서 현재 Step을 실행하지 않았다면 StepExecution을 생성하지 않는다. Step이 실제로 시작되었을 때만 StepExecution을 생성한다.
- JobExecution과의 관계
- Step의 StepExecution이 모두 정상적으로 완료되어야 JobExecution이 정상적으로 완료된다.
- Step의 StepExecution중 하나라도 실패하면 JobExecution은 실패한다.
2) BATCH_STEP_EXECUTION 테이블과 매핑
- JobExecution과 StepExecution은 1:N의 관계
- 하나의 Job을 여러 개의 Step으로 구성했을 경우 각 StepExecution은 하나의 JobExecution을 부모로 가진다.
2-1) Step1, Step2 모두 성공한 케이스
BATCH_JOB_EXECUTION
JobExecution ID JobInstance ID Start Time End Time Status 1 1 2021.01.01.12:00 2021.01.01.12:10 COMPLETED BATCH_STEP_EXECUTION
StepExecution ID Step Name JobExecution ID Status 1 Step1 1 COMPLETED 2 Step2 1 COMPLETED 2-2) Step1 성공, Step2 실패한 케이스
BATCH_JOB_EXECUTION
JobExecution ID JobInstance ID Start Time End Time Status 2 2 2021.01.02.12:00 2021.01.02.12:10 FAILED BATCH_STEP_EXECUTION
StepExecution ID Step Name JobExecution ID Status 3 Step1 2 COMPLETED 4 Step2 2 FAILED 2-3) JobInstanceA 성공, JobInstanceB 실패, JobInstanceB 재시도 성공 케이스 도식화
3) StepExecution 속성
실습
실습 1) step1, step2, step3 모두 성공
더보기StepConfiguration.java 전체 소스코드
@RequiredArgsConstructor @Configuration public class StepConfiguration { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; @Bean public Job BatchJob() { return this.jobBuilderFactory.get("Job") .start(step1()) .next(step2()) .next(step3()) .build(); } @Bean public Step step1() { return stepBuilderFactory.get("step1") .tasklet(new Tasklet() { // 편의상 익명클래스를 사용했지만 클래스로 만들어도 된다. step3 참고 // StepBuilder.tasklet -> TaskletStepBuilder을 반환한다. // TaskletStepBuilder : Tasklet을 만들어주는 빌더클래스. @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("step1 has executed"); return RepeatStatus.FINISHED; } }) .build(); // AbstractTaskletStepBuilder.build -> TaskletStep을 반환한다. } @Bean public Step step2() { // 람다로 구성 return stepBuilderFactory.get("step2") .tasklet((contribution, chunkContext) -> { System.out.println("step2 has executed"); return RepeatStatus.FINISHED; }) .build(); } @Bean public Step step3() { return stepBuilderFactory.get("step3") .tasklet(new CustomTasklet()) .build(); } }
- BATCH_JOB_EXECUTION 테이블
SELECT JOB_EXECUTION_ID, JOB_INSTANCE_ID, STATUS, EXIT_CODE, EXIT_MESSAGE FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = 13
- BATCH_STEP_EXECUTION 테이블
SELECT STEP_EXECUTION_ID, STEP_NAME, JOB_EXECUTION_ID, STATUS, COMMIT_COUNT, ROLLBACK_COUNT, EXIT_CODE, EXIT_MESSAGE FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = 13
실습 2) step2에서 에러 발생
@Bean public Step step2() { // 람다로 구성 return stepBuilderFactory.get("step2") .tasklet((contribution, chunkContext) -> { System.out.println("step2 has executed"); throw new RuntimeException("step2 has failed"); // return RepeatStatus.FINISHED; }) .build(); }
2024-02-15 07:06:29.343 INFO 11781 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=Job]] launched with the following parameters: [{name=user3}] 2024-02-15 07:06:29.378 INFO 11781 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [step1] step1 has executed 2024-02-15 07:06:29.403 INFO 11781 --- [ main] o.s.batch.core.step.AbstractStep : Step: [step1] executed in 25ms 2024-02-15 07:06:29.427 INFO 11781 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [step2] step2 has executed 2024-02-15 07:06:29.439 ERROR 11781 --- [ main] o.s.batch.core.step.AbstractStep : Encountered an error executing step step2 in job Job java.lang.RuntimeException: step2 has failed at io.springbatch.springbatchlecture.StepConfiguration.lambda$step2$0(StepConfiguration.java:50) ~[classes/:na]
- BATCH_JOB_EXECUTION 테이블
SELECT JOB_EXECUTION_ID, JOB_INSTANCE_ID, STATUS, EXIT_CODE, EXIT_MESSAGE FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = 14
- BATCH_STEP_EXECUTION 테이블
SELECT STEP_EXECUTION_ID, STEP_NAME, JOB_EXECUTION_ID, STATUS, COMMIT_COUNT, ROLLBACK_COUNT, EXIT_CODE, EXIT_MESSAGE FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = 14
step1 COMPLETED, step2가 FAILED 상태로 남고 step3에 대한 step execution은 생성되지 않았다. 실습 3) 실습2 재시도
- BATCH_JOB_EXECUTION 테이블
SELECT JOB_EXECUTION_ID, JOB_INSTANCE_ID, STATUS, EXIT_CODE, EXIT_MESSAGE FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = 15
- BATCH_STEP_EXECUTION 테이블
SELECT STEP_EXECUTION_ID, STEP_NAME, JOB_EXECUTION_ID, STATUS, COMMIT_COUNT, ROLLBACK_COUNT, EXIT_CODE, EXIT_MESSAGE FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = 15
step2만 FAILED로 남고 실행되지 않은 step1(이미 성공), step3(이전에 실패)에 대한 step execution은 생성되지 않았다. 실습 4) 실습3 성공으로 변경하여 재시도
@Bean public Step step2() { // 람다로 구성 return stepBuilderFactory.get("step2") .tasklet((contribution, chunkContext) -> { System.out.println("step2 has executed"); // throw new RuntimeException("step2 has failed"); return RepeatStatus.FINISHED; }) .build(); }
- BATCH_JOB_EXECUTION 테이블
SELECT JOB_EXECUTION_ID, JOB_INSTANCE_ID, STATUS, EXIT_CODE, EXIT_MESSAGE FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = 16
- BATCH_STEP_EXECUTION 테이블
SELECT STEP_EXECUTION_ID, STEP_NAME, JOB_EXECUTION_ID, STATUS, COMMIT_COUNT, ROLLBACK_COUNT, EXIT_CODE, EXIT_MESSAGE FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = 16
step2, step3이 COMPLETED로 남고 이미 성공하여 실행되지 않은 step1의 step execution은 생성되지 않았다. 'Study > Spring Batch' 카테고리의 다른 글
스프링 배치 도메인 이해 -ExecutionContext (0) 2024.02.29 스프링 배치 도메인 이해 -StepContribution (0) 2024.02.15 스프링 배치 도메인 이해 -Step (0) 2024.02.15 스프링 배치 도메인 이해 -JobExecution (0) 2024.02.08 스프링 배치 도메인 이해 -JobParameter (1) 2024.02.08 - Step에 대한 한 번의 시도를 의미하는 객체로 Step 실행 중에 발생한 정보들을 저장하고 있는 객체.