2024.03.27 - [Spring/결제] - Spring으로 결제서비스 만들기(1)
이전글에서는 정산팀은 1일 단위로 정산이라는 조건까지 구현을 완료했다.
- 매주 금요일 1주일치 1일 정산을 집계해서 DB에 저장 후, 고객사에 이메일 보냄 // 고객번호, 서비스번호, 횟수, 요금
이번에는 위 조건에 대해 확장을 해보도록 한다.
일주일치 csv파일을 만들어야하니 7개의 Worker Step을 만드는 Patitioning 기법을 통해 만든다.
ApiOrderGeneratePartitionJobConfiguration.java
@Configuration
@RequiredArgsConstructor
public class ApiOrderGeneratePartitionJobConfiguration {
private final JobRepository jobRepository;
private final PlatformTransactionManager platformTransactionManager;
@Bean
public Job apiOrderGenerateJob(Step managerStep){
return new JobBuilder("apiOrderGenerateJob", jobRepository)
.start(managerStep)
.incrementer(new RunIdIncrementer())
.validator(new DefaultJobParametersValidator(new String[]{"targetDate", "totalCount"}, new String[0]))
.build();
}
@Bean
@JobScope
public Step managerStep(
PartitionHandler partitionHandler,
@Value("#{jobParameters['targetDate']}") String targetDate,
Step apiOrderGenerateStep
){
return new StepBuilder("managerStep", jobRepository)
.partitioner("delegateStep", getPartitioner(targetDate))
.step(apiOrderGenerateStep)
.partitionHandler(partitionHandler)
.build();
}
//매니저 스텝이 워커 스텝을 어떻게 다룰지를 정의
@Bean
public PartitionHandler partitionHandler(Step apiOrderGenerateStep){
TaskExecutorPartitionHandler taskExecutorPartitionHandler = new TaskExecutorPartitionHandler();
taskExecutorPartitionHandler.setStep(apiOrderGenerateStep);
taskExecutorPartitionHandler.setGridSize(7);
taskExecutorPartitionHandler.setTaskExecutor(new SimpleAsyncTaskExecutor());
return taskExecutorPartitionHandler;
}
//워커 스텝을 위해서 StepExecution을 생성하는 인터페이스
Partitioner getPartitioner(String targetDate){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate date = LocalDate.parse(targetDate, formatter);
//파티션별 이름과, 사용할 ExecutionContext 지정
return x -> {
final Map<String, ExecutionContext> result = new HashMap<>();
IntStream.range(0, 7)
.forEach(it ->{
ExecutionContext value = new ExecutionContext();
value.putString("targetDate",date.minusDays(it).format(formatter));
result.put("partition" + it, value);
});
return result;
};
}
@Bean
public Step apiOrderGenerateStep(
ApiOrderGenerateReader apiOrderGenerateReader,
ApiOrderGenerateProcessor apiOrderGenerateProcessor
){
return new StepBuilder("apiOrderGenerateStep",jobRepository)
.<Boolean, ApiOrder>chunk(5000, platformTransactionManager)
.reader(apiOrderGenerateReader)
.processor(apiOrderGenerateProcessor)
.writer(apiOrderGenerateWriter(null))
.build();
}
@Bean
@StepScope //lazy로딩이 일어나 null이 인자로 들어가는것이 아니라, 맞는 데이터가 들어감
public FlatFileItemWriter<ApiOrder> apiOrderGenerateWriter(
@Value("#{stepExecutionContext['targetDate']}") String targetDate
){
String fileName = targetDate + "_api_orders_csv";
return new FlatFileItemWriterBuilder<ApiOrder>()
.name("apiOrderGenerateWriter")
.resource(new PathResource("/FastCampus/spring-payment/spring-payment/src/main/resources/datas/" + fileName))
.delimited() //기본값으로 두면 쉼표로구분
.names("id", "customerId", "url", "state", "createdAt")
.headerCallback(writer -> writer.write("id, customerId, url, state, createdAt"))
.build();
}
}
파티셔닝 기법을 위해서, 매니저 스텝을 따로 만들고 매니저 스텝이 파티션 핸들러를 통해 워커스텝이 어떻게 실행될지 설정해주고, 파티셔너를 통해 사용할 ExecutionContext를 지정 해줬다.
원래 apiOrderGenerateWriter에서 @StepScope 어노테이션으로 인해 @Value로 받아왔던 jobParameters를 확장된 코드에서는 StepExecution을 파티셔너에서 설정해주므로 @Value를 stepExecution에서 받아온다.
잘 실행되는 것을 확인할 수있다.
실행시간을 확인하기 위해서 콘솔뿐만 아니라, BATCH_STEP_EXECUTION 테이블에서도 확인할 수있다.
하지만 보다시피 시작, 끝 시점만 알려줘서 실행에 걸린 시간을 알고싶으면 계산을해야한다.
이를 또 스프링에서는 다 준비를 해놨다.
https://docs.spring.io/spring-batch/reference/monitoring-and-metrics.html#built-in-metrics
스프링 공식문서를 보면, Job, Step, Item에 대해서 모두 TIMER를 제공하고있다. 대다나다,,,
이제 csv로 만든 파일을 읽어서 특정고객에게 과금되는 금액을 알려주는 일일 정산배치를 만들어 보겠다.
2024.03.28 - [Spring/결제] - Spring으로 결제서비스 만들기(3)
'Spring > 결제' 카테고리의 다른 글
Spring으로 결제서비스 만들기(4) (1) | 2024.03.31 |
---|---|
Spring으로 결제서비스 만들기(3) (0) | 2024.03.28 |
Spring으로 결제서비스 만들기(1) (0) | 2024.03.27 |