Spring Batch - 11. ExecutionContext

출처

목차

ExecutionContext

프레잌워크에서 유지 및 관리하는 Key/Value 컬렉션으로 JobExecution, StepExecution 객체의 상태를 저장하는 공유 객체

  • DB 에 직렬화 한 값으로 저장된다.
  • Job 재 시작시 이미 처리한 Row 데이터는 건너뛰고 이후로 수행하도록 할 때 상태 정보를 활용한다.

ExecutionContext 는 Job 또는 Step 의 실행 중에 데이터를 공유하거나 저장하기 위한 메커니즘으로 JobExecution, StepExecution 및 JobParameter 와 함께 사용됩니다.

ExecutionContext 는 JobExecutionContext 와 StepExecutionContext 로 구분됩니다. JobExecutionContext 는 Job 의 실행 컨텍스트를 나타내며, StepExecutionContext 는 Step 의 실행 컨텍스트를 나타냅니다. JobExecutionContext 는 모든 Step에서 공유됩니다. 그러나 StepExecutionContext 는 Step 간에 공유되지 않으며, 각 Step 에서 고유한 ExecutionContext 를 유지합니다.

ExecutionContext 는 기본적으로 Map<String, Object> 타입으로 사용자가 직접 데이터를 추가, 수정, 삭제할 수 있습니다. 예를 들어, Job 또는 Step 실행 중에 사용자 데이터를 저장하고 싶은 경우, ExecutionContext 를 사용하여 저장할 수 있습니다.

Spring Batch에서 ExecutionContext 를 사용하면 다음 Step 에서 이전 Step 에서 처리된 데이터를 전달하거나 Job 에서 여러 Step 에서 공유하는 데이터를 전달할 수 있습니다. ExecutionContext 를 사용하여 Job 또는 Step 간 데이터 공유를 효율적으로 관리할 수 있습니다.

ExecutionContext 공유 범위

  • JobExecutionContext 범위

    • 각 Job 의 JobExecution 에 저장되며 Job 간 서로 공유가 안되며 해당 Job 의 Step 간 서로 공유가 가능하다.
  • StepExecutionContext 범위

    • 각 Step 의 StepExecution 에 저장되며 Step 간 서로 공유가 안된다.

@RequiredArgsConstructor
@Configuration
public class ExecutionContextConfiguration {

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;

private final ExecutionContextTasklet1 executionContextTasklet1;
private final ExecutionContextTasklet2 executionContextTasklet2;
private final ExecutionContextTasklet3 executionContextTasklet3;
private final ExecutionContextTasklet4 executionContextTasklet4;

@Bean
public Job BatchJob() {
return this.jobBuilderFactory.get("Job")
.start(step1())
.next(step2())
.next(step3())
.next(step4())
.build();
}

@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.tasklet(executionContextTasklet1)
.build();
}
@Bean
public Step step2() {
return stepBuilderFactory.get("step2")
.tasklet(executionContextTasklet2)
.build();
}
@Bean
public Step step3() {
return stepBuilderFactory.get("step3")
.tasklet(executionContextTasklet3)
.build();
}
@Bean
public Step step4() {
return stepBuilderFactory.get("step4")
.tasklet(executionContextTasklet4)
.build();
}
}
@Component
public class ExecutionContextTasklet1 implements Tasklet {

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

ExecutionContext jobExecutionContext = contribution.getStepExecution().getJobExecution().getExecutionContext();
ExecutionContext stepExecutionContext = contribution.getStepExecution().getExecutionContext();

String jobName = chunkContext.getStepContext().getStepExecution().getJobExecution().getJobInstance().getJobName();
String stepName = chunkContext.getStepContext().getStepExecution().getStepName();

if(jobExecutionContext.get("jobName") == null){
jobExecutionContext.put("jobName", jobName);
}
if(stepExecutionContext.get("stepName") == null) {
stepExecutionContext.put("stepName", stepName);
}

System.out.println("jobName: " + jobExecutionContext.get("jobName"));
System.out.println("stepName: " + stepExecutionContext.get("stepName"));

return RepeatStatus.FINISHED;
}
}
@Component
public class ExecutionContextTasklet2 implements Tasklet {

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
ExecutionContext stepExecutionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext();

System.out.println("jobName: " + jobExecutionContext.get("jobName"));
System.out.println("stepName: " + stepExecutionContext.get("stepName"));

String stepName = chunkContext.getStepContext().getStepExecution().getStepName();
if(stepExecutionContext.get("stepName") == null) {
stepExecutionContext.put("stepName", stepName);
}
return RepeatStatus.FINISHED;
}
}
@Component
public class ExecutionContextTasklet3 implements Tasklet {

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

Object name = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name");

if(name == null){
chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("name", "user1");
throw new RuntimeException("step has failed");
}

return RepeatStatus.FINISHED;
}
}
@Component
public class ExecutionContextTasklet4 implements Tasklet {

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

System.out.println("name: " + chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name"));

return RepeatStatus.FINISHED;
}
}
Share