정산 상태는 DB에, 재처리 입력은 JSON에 둔 이유
정산 상태와 재처리 입력의 흐름
지급 판단 상태와 재처리 입력은 어디에 있고 성공·실패 뒤 어떻게 바뀌는가?
DB의 PROCESSING 상태를 확인한 뒤 JSON 지급 입력으로 지급대행 API를 호출하고, 성공하면 DB를 COMPLETED로 바꾸고 JSON 항목을 제거하며, 실패하면 JSON에 남겨 매일 10시·14시에 DB 상태를 다시 확인한 뒤 재시도합니다.
- 기준 상태DB PROCESSING지급 여부를 결정하는 상태 기준
- 입력JSON 지급 입력계산 결과와 실패 후 재처리할 입력
- 처리지급대행 APIPROCESSING인 건의 지급을 요청
- 결과DB COMPLETED·JSON 제거지급 성공 항목을 완료 처리
- 결과JSON 실패 항목 보존다음 스케줄에서 다시 사용할 입력
- DB PROCESSING상태 재확인JSON 지급 입력
- JSON 지급 입력지급 입력 사용지급대행 API
- 지급대행 API지급 성공DB COMPLETED·JSON 제거
- 지급대행 API지급 실패JSON 실패 항목 보존
- JSON 실패 항목 보존매일 10시·14시 재시도DB PROCESSING
지급 판단 기준은 DB 상태였습니다
하이패스의 백엔드와 정산 구조를 혼자 담당하면서 가장 중요하게 본 질문은 실패한 지급을 다시 시도할 때 무엇을 기준으로 이미 처리된 건을 구분할 것인가 였습니다.
정산 상태는 DB에서 PENDING → PROCESSING → COMPLETED로 바뀌었습니다. 지급 요청 직전에도 UUID로 DB 상태를 다시 조회했고, PROCESSING 상태인 건만 지급대행사에 보냈습니다. 이미 COMPLETED인 건은 다시 지급하지 않았습니다. 지급 여부를 결정하는 기준은 JSON 파일이 아니라 DB 상태였습니다.
JSON에는 계산 결과와 재처리 입력을 남겼습니다
정산 금액과 대상을 만들려면 여러 조건을 결합한 복잡한 쿼리와 계산이 필요했습니다. JSON 파일에는 그 결과인 정산 대상·금액·지급 입력을 저장했습니다. 실패 뒤 같은 계산 결과를 다시 사용할 수 있게 하는 보조 저장소였고, 정산 상태의 원본은 아니었습니다.
이 분리는 두 저장소가 같은 책임을 갖는다는 뜻이 아닙니다. DB는 지급 가능 상태를 판단하고, JSON은 지급 호출에 필요한 계산 결과를 전달했습니다. 재시도에서도 JSON만 믿지 않고 DB 상태를 다시 확인했습니다.
성공은 제거하고 실패는 보존했습니다
지급 성공 시 DB 상태를 COMPLETED로 바꾼 뒤 해당 항목을 JSON에서 제거했습니다. 지급 실패 시에는 JSON에 실패 항목을 남겼습니다. 남은 항목은 매일 10시·14시 스케줄에서 재시도하며, 호출 전에 DB 상태를 다시 확인했습니다.
따라서 파일이 남아 있다는 사실만으로 지급하지 않았습니다. PROCESSING인 건만 다시 호출했고, 이미 COMPLETED라면 건너뛰었습니다.
실행 주체는 단일 PM2 프로세스로 분리했습니다
정산 스케줄러는 웹 서버와 별도인 단일 PM2 프로세스로 실행했습니다. 다중 웹 워커마다 스케줄이 실행되어 중복 실행되는 것을 막고, 정산 작업의 오류와 자원 사용을 웹 요청 처리에서 분리하기 위한 선택이었습니다.
이 구조는 한 서버 안에서 실행 주체를 하나로 제한한 것입니다. 여러 서버가 같은 로컬 파일을 공유하거나 분산 잠금을 제공하는 구조는 아니었습니다.
운영에서 확인한 범위
정산은 월 2회 실행됐습니다. 운영팀은 월말 보고서를 만들 때 내부 정산 내역과 지급대행사의 실제 지급 내역을 대조했습니다. 2026년 6월까지 반복한 대사 범위에서는 정산 금액 불일치와 중복 지급을 확인하지 못했습니다.
같은 기간에 JSON 파일 유실·손상·중복 실행 문제도 확인하지 못했습니다. 다만 이는 단일 서버의 실제 운영과 월말 대사에서 관찰한 범위이며, 모든 장애 상황을 자동 검증했거나 무결성을 보장한다는 의미는 아닙니다.
적용할 조건과 피해야 할 조건
로컬 JSON을 재처리 입력으로 두는 방식은 단일 서버·단일 스케줄러·작은 정산 규모처럼 파일의 소유권과 실행 주체가 분명할 때 적용할 수 있습니다.
반대로 로드밸런싱이나 스케일 아웃이 필요한 환경에는 로컬 JSON을 그대로 적용하지 않습니다. 서버마다 파일이 갈라질 수 있고 어느 실행 주체가 처리할지 별도 경계가 필요하기 때문입니다.
지금 다시 본다면
현재는 실패 입력을 Redis에 둘지, DB만으로 관리할지, 스케줄러 실행 구조를 바꿀지 고민하고 있습니다. 아직 세 방식을 비교하거나 검증하지 않았으므로 어느 하나를 정답이나 확정 계획으로 공개하지 않습니다. 먼저 파일 유실, 중복 실행, 여러 서버의 실행 주체처럼 해결하려는 조건을 명확히 한 뒤 선택해야 한다고 봅니다.