[Today I Learned - 8] Spring Batch에서 Step간 데이터 공유
1. Execution Context
스프링 배치에서는 Execution Context를 통해 데이터를 공유할 수 있으며 Execution Context는 Job 전체에 유지되는 Job Execution Context와 각 Step에서만 유지되는 Step Execution 으로 구분할 수 있다.
- Job Execution Context 는 각 Step이 종료되는 시점에 업데이트
- Step Execution Context 는 각 Tasklet? Chunk? 가 종료되는 시점에 업데이트
Step 간의 데이터를 공유하기 위해서는 Job 단위로 데이터가 유지되어야 하기 때문에 Job Execution Context를 사용해야한다.
2. ExecutionContextPromotionListener
Job Context Execution을 직접 참조하여 공유할 데이터를 설정할 수 있지만 이러한 경우 Job과 Step 간에 강한 결합이 생기는 문제가 생긴다. 또한 Step 이 정상적으로 종료되는 경우 데이터가 손실될 수 있기 때문에 스프링배치에서는 ExecutionContextPromotionListener를 이용하여 Step간 데이터를 공유하도록 권장하고 있다.
ExecutionContextPromotionListener는 Step이 끝나는 시점에 미리 설정한 key 값이 Step Context Execution에 존재한다면 이 데이터를 Job Step Execution으로 승격시키는 역할을 수행한다.
ExecutionContextPromotionListener 적용
Listener를 정의하고 Step에 설정하는 코드
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[]{CANCELED_DUE_TO_REJECT_TAX, NTS_SEND_FAIL_TAX});
return listener;
}
@Bean
public Step ntsSendFailNotifyStep() {
return new StepBuilder("ntsSendFailNotifyStep", jobRepository)
.tasklet(ntsSendFailNotifyTasklet(), transactionManager)
.listener(promotionListener())
.build();
}
3. Step 간 데이터 공유
ExecutionContextPromotionListener에서 설정한 키 값(NTS_SEND_FAIL_TAX, CANCELED_DUE_TO_REJECT_TAX) 으로 Step Execution Context에 "data1"과 "data2"를 저장하고 있다.
@Bean
public Tasklet save_tasklet() {
return (contribution, chunkContext) -> {
ExecutionContext executionContext = contribution.getStepExecution().getExecutionContext();
executionContext.put(NTS_SEND_FAIL_TAX, "data1");
executionContext.put(CANCELED_DUE_TO_REJECT_TAX, "data2");
return RepeatStatus.FINISHED;
};
}
ExecutionContextPromotionListener에 의해 Step Execution Context에서 Job Execution Context로 승격했기 때문에 저장한 값을 참조할 때는 Job Execution Context를 통해 값을 참조해야 한다.
@Bean
public Tasklet get_tasklet() {
return (contribution, chunkContext) -> {
JobExecution jobExecution = contribution.getStepExecution().getJobExecution();
ExecutionContext executionContext = jobExecution.getExecutionContext();
String data1 = (String) executionContext.get(NTS_SEND_FAIL_TAX);
String data2 = (String) executionContext.get(CANCELED_DUE_TO_REJECT_TAX);
return RepeatStatus.FINISHED;
};
}