- Tasklet -
1) Tasklet?
- Step을 구현할 때 구현방법에는 크게 Tasklet 방식이 있고 Chunk 방식이 있다.
- Tasklet은 Chunk보다 단순한 방식으로 단일 작업을 구현한다.
- EX
public interface Tasklet {
@Nullable
RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception;
}
- StepBuilderFactory로 Step을 만들 때 tasklet()안에다가 구현한 Tasklet을 넣어주면 된다.
- 아래 예시의 경우에는 sampleStep은 넣어준 sampleTasklet로 동작하게 된다.
return stepBuilderFactory.get("sampleStep")
.transactionManager(transactionManager)
.tasklet(sampleTasklet)
.build();
2) Tasklet의 상태
- Tasklet의 상태는 계속 진행할지, 끝낼지 두가지로만 표현.
- RepeatStatus.FINISHED가 반환되면 tasklet이 바로 끝나고 RepeatStatus.CONTINUABLE이 반환되면 Tasklet을 다시 실행. 따라서RepeatStatus.CONTINUABLE를 반환한 예제는 영구적으로 끝나지 않고 계속해서 로그를 남깁니다. null을 반환하면 FINISHED와 동일하게 인지한다.
/**
* 무한히 종료되지 않는 Tasklet이다.
* 아래와 같이 구현하면 안된다.
**/
@Bean
@StepScope
public Tasklet sampleTasklet() {
return (contribution, chunkContext) -> {
log.info("never ending tasklet");
return RepeatStatus.CONTINUABLE;
};
}
/**
* inish를 log에 찍고 종료하는 Tasklet이다.
**/
@Bean
@StepScope
public Tasklet sampleTasklet() {
return (contribution, chunkContext) -> {
log.info("finish");
return RepeatStatus.FINISHED;
};
}
3) Tasklet을 만들 때 주의할점
@Bean
@StepScope
public Tasklet hugeReadTasklet(
PriceRepository priceRepository
) {
return (contribution, chunkContext) -> {
// findByDate로 조회된 데이터가 1천만개 입니다.
List<Price> prices = priceRepository.findByDate(LocalDate.now());
// price를 모두 0으로 초기화합니다.
prices.forEach(price -> price.setAmount(0L));
// 1천만개의 데이터를 저장합니다.
priceRepository.saveAll(prices);
return RepeatStatus.FINISHED;
};
}
- priceRepository.findByDate를 통해서 얼마나 많은 데이터를 가져올지 예측이 불가. 데이터가 너무 많다면 천만개의 데이터를 조회할 수도 있습니다. 천만개의 데이터를 한번에 가져온다면 메모 리 이슈로 인해 처리가 불가해지고 OOM(Out Of Memory)이 발생할 수 도 있습니다.