[Spring Boot] Spring Batch 적용하기

Sungjin Cho·2024년 7월 19일
0

Spring Boot

목록 보기
5/15
post-thumbnail

Spring Batch

todo

  1. 매일 자정 db dump해서 복사본 로컬 디렉토리에 저장
  2. 매일 자정 유통기한 확인해서 할인율 및 updated_date 업데이트

Spring Batch와 @Scheduled의 차이점 (by Claude AI)

  • Spring Batch:
    • 대용량 데이터 처리를 위한 프레임워크입니다.
    • 복잡한 작업 흐름을 정의하고 관리할 수 있습니다.
    • 작업의 재시작, 중지, 건너뛰기 등 세밀한 제어가 가능합니다.
    • 데이터 처리 과정을 단계별로 나누어 관리할 수 있습니다.
    • 작업 실행 이력을 데이터베이스에 저장하고 관리합니다.
    • 대규모 데이터 마이그레이션, 복잡한 리포트 생성 등에 적합합니다.
  • @Scheduled:
    • 간단한 주기적 작업 실행에 적합합니다.
    • 설정이 간편하고 빠르게 구현할 수 있습니다.
    • 작업 실행 이력 관리나 세밀한 제어 기능이 없습니다.
    • 애플리케이션 내에서 주기적으로 실행되는 작은 규모의 작업에 적합합니다.

처음에는 batch를 쓸 필요성을 못느끼고 @Scheduled 어노테이션을 사용해서 자정마다 살행되도록 할 생각이었다. 1번 케이스의 경우에는 대용량 데이터 처리 없이 단순히 dump 명령어만을 사용하여 파일을 저장하기만 하면 되기 때문에 batch를 쓸 필요는 없었다. 하지만 2번의 경우에는 상품이 많아지면 update해야 할 row들이 늘어나기 때문에 데이터 처리 과정을 관리할 필요가 있었기 때문에 @Scheduled 와 Spring Batch 를 같이 사용하기로 하였다. 또한 Spring Batch를 사용하게 되면 batch 테이블에 작업 내용이 자동으로 저장되기 때문에 작업 실행 이력을 추적하고 관리하기에도 용이하다고 판단했다.

Spring Batch 적용

  1. 실행할 job과 step을 bean으로 정의한다.

@Configuration
@Slf4j
public class ExpirationDateUpdateJob {

    private final JobRepository jobRepository;
    private final PlatformTransactionManager transactionManager;
    private final ShopItemRepository shopItemRepository;
    private final ShopProductPriceRepository shopProductPriceRepository;

    @Value("${product.discount.threshold.days}")
    private int expirationThresholdDays;

    @Value("${product.expiration.discountRatio}")
    private int expirationDiscountRatio;

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    public ExpirationDateUpdateJob(JobRepository jobRepository,
                                   PlatformTransactionManager transactionManager,
                                   ShopItemRepository shopItemRepository,
                                   ShopProductPriceRepository shopProductPriceRepository) {
        this.jobRepository = jobRepository;
        this.transactionManager = transactionManager;
        this.shopItemRepository = shopItemRepository;
        this.shopProductPriceRepository = shopProductPriceRepository;
    }

    @Bean
    public Job updateExpirationDateJob(Step updateExpirationDateStep) {
        return new JobBuilder("updateExpirationDateJob", jobRepository)
                .start(updateExpirationDateStep)
                .build();
    }

    @Bean
    public Step updateExpirationDateStep() {
        return new StepBuilder("updateExpirationDateStep", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    List<ShopItem> expiringItems = shopItemRepository.checkExpirationDate(expirationThresholdDays);

                    List<String> itemIdsToUpdate = expiringItems.stream()
                            .map(ShopItem::getId)
                            .collect(Collectors.toList());

                    if (!itemIdsToUpdate.isEmpty()) {
                        shopProductPriceRepository.updateDiscountForItems(itemIdsToUpdate, expirationDiscountRatio);
                        log.info("Updated discount for {} items", itemIdsToUpdate.size());

                        for (ShopItem item : expiringItems) {
                            log.info("Updated item - Name: {}, Distribution Period: {}",
                                    item.getName(),
                                    dateFormat.format(item.getDistributionPeriod()));
                        }
                    } else {
                        log.info("No items to update");
                    }

                    return RepeatStatus.FINISHED;
                }, transactionManager)
                .build();
    }
}

ExpirationDateUpdateJob:

Spring Batch Job을 정의하는 설정 클래스다.
@Configuration 어노테이션으로 Spring 설정 클래스임을 표시한다.
Job과 Step을 Bean으로 정의한다.
updateExpirationDateStep에서 실제 작업을 수행한다:

유통기한 임박 상품 조회
해당 상품들의 할인율 업데이트
업데이트된 상품 정보 로그 기록

  1. 정의한 job에 대해서 @Scheduled 어노테이션을 통해 특정 시간마다 실행되도록 Scheduler를 정의한다.
@Component
@Slf4j
@RequiredArgsConstructor
public class ExpirationDateUpdateScheduler {

    private final JobLauncher jobLauncher;
    private final Job updateExpirationDateJob;

    //@Scheduled(cron = "0 * * * * ?")  // 매 분마다 실행
    //@Scheduled(cron = "0 0 0 * * ?")  // 매일 0시마다 실행
    @Scheduled(cron = "0 0 * * * ?")  // 매 시간 0분마다 실행
    public void runUpdateExpirationDateJob() {
        try {
            JobParameters jobParameters = new JobParametersBuilder()
                    .addLong("time", System.currentTimeMillis())
                    .toJobParameters();
            jobLauncher.run(updateExpirationDateJob, jobParameters);
        } catch (Exception e) {
            log.error("Error occurred while running update expiration date job: ", e);
        }
    }
}

@Scheduled 어노테이션으로 주기적 Job 실행을 담당하는 스케줄러다.
@Component 어노테이션으로 Spring Bean 등록
JobLauncher로 ExpirationDateUpdateJob 실행
현재 매 시간 0분마다 Job 실행 설정

0개의 댓글