4단계: 일마감 정산 배치 (배치 기술)
6. 다음 단계로
네 단계가 끝났다. 1단계의 Member[3]에서 시작해 4단계의 10만 건 정산 배치까지, 같은 도메인이 성장했다. 각 단계에서 도입한 기술이 왜 필요했는지를 돌아본다.
| 단계 | 막힌 것 | 도입한 기술 |
|---|---|---|
| 1 → 2 | 배열 크기, 선형 탐색, null, 산만한 실패 처리, 계산 중복, 결제 수단 분기 | 컬렉션, 예외 계층, 값 객체, 인터페이스/추상 클래스, Repository |
| 2 → 3 | 저장소 중복, null 반복, 명령형 집계, 정책 클래스 폭발, 동시 주문 오염 | 제네릭, Optional, 스트림, 람다 조합, ExecutorService + 원자적 갱신, record/sealed |
| 3 → 4 | 전부 메모리, 실패 시 처음부터, 반쯤 반영, 한 건이 전체를 멈춤, 게이트웨이 장애, 출력 원자성 | 청크, 체크포인트, 트랜잭션 시뮬레이션, 스킵, 재시도, 원자적 이동 |
4단계 코드에도 남은 것이 있다. 이것들은 이 커리큘럼 밖(프레임워크, DB, 운영)의 주제라 여기서는 방향만 적는다.
| 남은 한계 | 실무의 해법 |
|---|---|
| 청크 안에서 결제가 순차 | 청크 내 병렬 처리(ExecutorService). JobState 는 스레드 안전하게 |
| 체크포인트가 파일 | DB 테이블(BATCH_STEP_EXECUTION). 메타와 업무 데이터를 같은 트랜잭션에 |
| 멱등성이 시뮬레이션 | 게이트웨이의 멱등키, 또는 "결제 요청 전 상태를 먼저 기록"하는 아웃박스 패턴 |
| 스케줄링 없음 | cron, Spring Scheduler, Airflow — "매일 02:00 실행, 실패 시 알림, 재실행" |
| 단일 파일 입력 | DB 페이징 조회, 메시지 큐, 파티션 분할(파일을 N개로 나눠 병렬 잡) |
로그가 println |
구조화 로깅(잡 ID, 청크 번호, 행 번호를 필드로), 메트릭(처리율, 스킵률) 수집 |
이 프로젝트를 Spring Batch로 옮기면 대응은 다음과 같다.
ChunkReader→FlatFileItemReaderOrderParser→ItemProcessorSettlementWriter→ItemWriterRetryTemplate→@Retryable/faultTolerant().retry()SkipException→.skip()CheckpointStore→JobRepository
이름만 바뀌고 개념은 그대로다. 프레임워크를 배울 때 "이게 왜 있지?"가 아니라 "아, 그거구나"가 되는 것 — 그것이 이 4단계 프로젝트의 목적이었다.