피드로 돌아가기
Building a Payment Processor: The Final One Percent
Dev.toDev.to
Backend

Lease 기반 상태 관리와 Tx 외부 호출로 Double Charge 원천 차단

Building a Payment Processor: The Final One Percent

Oreoluwa Bimbo-Salami2026년 5월 7일3advanced

Context

Idempotency와 Message Queue를 도입했음에도 Worker Crash 시 결제 상태가 'processing'에 고착되는 Orphaned Payment 문제 발생. 외부 API 호출을 DB Transaction 내부에 포함시켜 Commit 실패 시 중복 결제가 발생하는 구조적 결함 확인.

Technical Solution

  • Processing Lease 도입을 통한 상태 고착 해결: processing_started_at 타임스탬프를 기록하고 2분 초과 시 Worker 장애로 판단하는 Sweeper 로직 설계
  • 'Commit Before Charge' 원칙 적용: 외부 Provider 호출 전 상태 업데이트 및 Transaction Commit을 완료하여 DB 롤백으로 인한 중복 요청 방지
  • External Call의 Transaction 외부 배치: DB 연결 유지 시간을 최소화하고 외부 API의 Idempotency Key를 활용한 재시도 안전성 확보
  • OpenTelemetry 기반 Distributed Tracing 구축: Trace-ID를 RabbitMQ 메시지에 포함하여 API-Queue-Worker로 이어지는 전체 요청 경로의 가시성 확보
  • Outbox Pattern 적용: API 요청 시 결제 정보와 Outbox Entry를 단일 트랜잭션으로 처리하여 메시지 발행 보장

- 외부 API 호출 전 반드시 DB Transaction을 Commit 했는지 확인 - 장시간 'Processing' 상태에 머무는 레코드를 처리할 Sweeper/Reconciliation Job 설계 여부 검토 - Distributed System에서 로그 기반 추적이 아닌 Trace-ID 기반의 전 구간 추적 환경 구축 - 외부 Provider의 Idempotency 기능을 활용한 재시도 전략 수립

원문 읽기