반응형
728x90
반응형
Job 생성
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.FlowBuilder;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
--job.name=startNextJob
*/
@Configuration
@RequiredArgsConstructor
public class StartNextConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job startNextJob() {
return this.jobBuilderFactory.get("startNextJob")
.start(flowA())// step1, step2
.next(startNextStep3())
.next(flowB()) // step4, step5
.next(startNextStep6())
.end()
.build();
}
@Bean
public Flow flowA() {
FlowBuilder<Flow> flowBuilder = new FlowBuilder<>("flowA");
flowBuilder.start(startNextStep1())
.next(startNextStep2())
.end();
return flowBuilder.build();
}
@Bean
public Flow flowB() {
FlowBuilder<Flow> flowBuilder = new FlowBuilder<>("flowA");
flowBuilder.start(startNextStep4())
.next(startNextStep5())
.end();
return flowBuilder.build();
}
@Bean
public Step startNextStep1() {
return stepBuilderFactory.get("startNextStep1")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep1");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step startNextStep2() {
return stepBuilderFactory.get("startNextStep2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep2");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step startNextStep3() {
return stepBuilderFactory.get("startNextStep3")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep3");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step startNextStep4() {
return stepBuilderFactory.get("startNextStep4")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep4");
// 고의 에러 발생
// JOB FAILED
throw new RuntimeException("step4 was failed");
// return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step startNextStep5() {
return stepBuilderFactory.get("startNextStep5")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep5");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Step startNextStep6() {
return stepBuilderFactory.get("startNextStep2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep6");
return RepeatStatus.FINISHED;
}
})
.build();
}
}
실행 흐름
flowA() | startNextStep1() |
startNextStep2() | |
startNextStep3() | |
flowB() | startNextStep4() -> 고의 에러 발생 |
startNextStep5() | |
startNextStep6() |
DB 테이블 조회
1) BATCH_JOB_EXECUTION
COLUMN | VALUE |
STATUS | FAILED |
EXIT_CODE | FAILED |
JOB_EXECUTION_ID | 15 |
2) BATCH_JOB_INSTANCE
COLUMN | VALUE |
JOB_NAME | startNextJob |
3) BATCH_STEP_EXECUTION
- startNextStep1
COLUMN | VALUE |
STEP_NAME | startNextStep1 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 15 |
- startNextStep2
COLUMN | VALUE |
STEP_NAME | startNextStep2 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 15 |
- startNextStep3
COLUMN | VALUE |
STEP_NAME | startNextStep3 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 15 |
- startNextStep4
COLUMN | VALUE |
STEP_NAME | startNextStep4 |
EXIT_CODE | FAILED |
STATUS | FAILED |
JOB_EXECUTION_ID | 15 |
다시 정상 수행으로 변경
flowA() | startNextStep1() |
startNextStep2() | |
startNextStep3() | |
flowB() | startNextStep4() -> 정상 수행되도록 변경 |
startNextStep5() | |
startNextStep6() |
startNextStep4() 변경
@Bean
public Step startNextStep4() {
return stepBuilderFactory.get("startNextStep4")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("startNextStep4");
// 고의 에러 발생
// JOB FAILED
// throw new RuntimeException("step4 was failed");
return RepeatStatus.FINISHED;
}
})
.build();
}
Job 재수행
이전에 실패했었던 startNextStep4 부터 수행된다.
실행 결과
startNextStep4
startNextStep5
startNextStep6
DB 테이블 조회
1) BATCH_JOB_EXECUTION
COLUMN | VALUE |
STATUS | COMPLETED |
EXIT_CODE | COMPLETED |
JOB_EXECUTION_ID | 16 |
2) BATCH_JOB_INSTANCE
COLUMN | VALUE |
JOB_NAME | startNextJob |
3) BATCH_STEP_EXECUTION
- startNextStep1
COLUMN | VALUE |
STEP_NAME | startNextStep1 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 16 |
- startNextStep2
COLUMN | VALUE |
STEP_NAME | startNextStep2 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 16 |
- startNextStep3
COLUMN | VALUE |
STEP_NAME | startNextStep3 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 16 |
- startNextStep4
COLUMN | VALUE |
STEP_NAME | startNextStep4 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 16 |
- startNextStep5
COLUMN | VALUE |
STEP_NAME | startNextStep5 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 15 |
- startNextStep6
COLUMN | VALUE |
STEP_NAME | startNextStep6 |
EXIT_CODE | COMPLETED |
STATUS | COMPLETED |
JOB_EXECUTION_ID | 16 |
반응형