package com.interplug.qcast.batch.master; import com.interplug.qcast.biz.displayItem.DisplayItemService; import com.interplug.qcast.biz.displayItem.dto.PriceItemSyncResponse; import com.interplug.qcast.biz.displayItem.dto.PriceSyncResponse; import com.interplug.qcast.util.InterfaceQsp; import java.util.Collections; import java.util.List; import java.util.function.Consumer; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.*; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.job.builder.JobBuilder; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.transaction.PlatformTransactionManager; /** Price 동기화 배치 */ @Configuration @Slf4j public class PriceJobConfiguration implements JobExecutionListener { private final InterfaceQsp interfaceQsp; private final DisplayItemService displayItemService; @Value("${qsp.master-price-batch-url}") private String qspInterfaceUrl; private PriceSyncResponse priceSyncResponse; public PriceJobConfiguration(InterfaceQsp interfaceQsp, DisplayItemService displayItemService) { this.interfaceQsp = interfaceQsp; this.displayItemService = displayItemService; } @Override public void beforeJob(JobExecution jobExecution) { log.info("Job 시작: 초기화 메서드 호출 중..."); try { this.priceSyncResponse = interfaceQsp.callApiData( HttpMethod.GET, qspInterfaceUrl + "?allYn=N", null, PriceSyncResponse.class); log.info("API 호출 완료, 항목 수: {}", this.priceSyncResponse.getModulePriceList().size()); } catch (Exception e) { log.error("priceSyncResponse 갱신 중 오류: {}", e.getMessage()); } } @Bean public Job priceJob(JobRepository jobRepository, Step modulePriceStep, Step bosPriceStep) { return new JobBuilder("priceJob", jobRepository) .start(modulePriceStep) .next(bosPriceStep) .listener(this) .build(); } private Step buildStep( String stepName, JobRepository jobRepository, PlatformTransactionManager transactionManager, ItemReader reader, ItemWriter writer) { return new StepBuilder(stepName, jobRepository) .chunk(100, transactionManager) .reader(reader) .writer(writer) .build(); } @Bean public Step modulePriceStep( JobRepository jobRepository, PlatformTransactionManager transactionManager) { return buildStep( "modulePriceStep", jobRepository, transactionManager, modulePriceListReader(), createWriter( (items) -> { try { log.debug("Module Price batch processing {} items", items.size()); displayItemService.setPriceSyncSave(items); log.debug("Successfully processed Module Price batch"); } catch (Exception e) { log.error("Error processing Module Price batch: {}", e.getMessage(), e); throw new RuntimeException("Failed to process Module Price batch", e); } }, "module price")); } @Bean public Step bosPriceStep( JobRepository jobRepository, PlatformTransactionManager transactionManager) { return buildStep( "bosPriceStep", jobRepository, transactionManager, bosPriceListReader(), createWriter( (items) -> { try { log.debug("Bos Price batch processing {} items", items.size()); displayItemService.setPriceSyncSave(items); log.debug("Successfully processed Bos Price batch"); } catch (Exception e) { log.error("Error processing Bos Price batch: {}", e.getMessage(), e); throw new RuntimeException("Failed to process Bos Price batch", e); } }, "bos price")); } private ListItemReader createReader(List items, String readerName) { log.info("{}Reader 호출됨...", readerName); return new ListItemReader<>(items != null ? items : Collections.emptyList()); } @Bean @StepScope public ListItemReader modulePriceListReader() { return createReader( priceSyncResponse != null ? priceSyncResponse.getModulePriceList() : null, "module"); } @Bean @StepScope public ListItemReader bosPriceListReader() { return createReader( priceSyncResponse != null ? priceSyncResponse.getBosPriceList() : null, "bos"); } private ItemWriter createWriter(Consumer> processor, String writerName) { return items -> { try { List itemList = (List) items.getItems(); processor.accept(itemList); log.info("{}Writer: {} items 처리 완료", writerName, items.size()); } catch (Exception e) { log.error("{}Writer 오류: {}", writerName, e.getMessage()); throw e; } }; } }