@Scheduled(cron = "0 0 0 * * *")
@Transactional
private void schedulingOpenRunProduct() throws InterruptedException{
updateProductStatus();
Long count = saveOpenRunCount();
saveOpenRunRedisCache(count);
saveAllProductCount();
}
//....
private void saveOpenRunRedisCache(Long count){
long totalPages = count / 16; // 17 => 1.xx 0, 1
for (int i = 0; i <= totalPages; i++) {
Pageable pageable = PageRequest.of(i, 16);
openRunProductRedisRepository.saveProduct(i, productRepository.findOpenRunProducts(OpenRunStatus.OPEN, pageable, count));
}
}
prob.1
서버의 수평 확장(scale out)될 때, 모든 서버에서 Scheduler가 동작하여, 불필요한 DB IO가 발생으로 DB 성능 저하
⇒ 1 대의 서버에서만 Scheduler가 동작할 수 있도록 설정이 필요
prob.2
위의 4개의 메서드는 순서가 중요하고, 별도의 트렌잭션 관리가 필요함. 또한, 예외 발생 시, 어떤 메소드에서 예외가 발생하였는지 기록이 어렵고, 재시도 로직을 별도로 만들어서 처리해야 함.
⇒ 로직의 복잡성 증가
prob.3
반복적인 작업(Page 단위로 상품을 조회 후, Redis에 저장)하는 과정에서, 일부 과정이 문제가 발생했을 시, 해당 메서드는 모든 작업이 종료됨
⇒ 반복 작업을 별도의 트렌잭션으로 처리 불가
<aside> 💡 Spring Batch 적용 ⬇️
</aside>
sol.1
각각의 매서드를 Step 단위로 분리 / 트랜잭션 관리@Bean
public Job productJob(
JobRepository jobRepository,
Step openRunProductUpdateStep,
Step openRunCountStep,
Step openRunSaveRedisStep,
Step saveAllProductCountStep) {
return new JobBuilder("productJob", jobRepository)
.start(openRunProductUpdateStep)
.on("FAILED").to(openRunCountStep)
.from(openRunProductUpdateStep).on("*").to(openRunCountStep)
.from(openRunCountStep)
.on("FAILED").to(openRunSaveRedisStep)
.from(openRunCountStep).on("*").to(openRunSaveRedisStep)
.from(openRunSaveRedisStep)
.on("FAILED").to(saveAllProductCountStep)
.from(openRunSaveRedisStep).on("*").to(saveAllProductCountStep)
.end()
.build();
}