#멱등성

결제 흐름 안의 물류 API 호출을 걷어내기 – 같은 트랜잭션 아웃박스 + 배치 릴레이 + Kafka 로 OMS 에 주문 넘기기

결제·취소 흐름 안에서 메시지를 바로 발행하고 물류 API 를 부르던 구조를, 주문과 주문 아웃박스를 한 MongoDB 트랜잭션에 저장하고 커머스의 배치 릴레이가 아웃박스를 폴링·CAS 선점해 Kafka 로 OMS 에 발행하는 구조로 바꾸는 설계다. 이미 운영 중인 조각과 앞으로 만들 조각을 나눠 적었다. 그리고 Kafka 를 고른 이유, exactly-once 대신 at-least-once + 멱등 소비를 고른 이유, CDC 를 쓰지 않은 이유, 장애 지점별 동작을 정리했다.

· 25분 읽기

알림을 한 번만, 그러나 잃지 않게 – 고객등급제 알림톡 발송을 outbox / inbox 로 다시 짠 기록

배치가 비즈뿌리오에 직접 보내고 나서 내역을 남기던 고객등급제 알림을, 배치는 outbox 테이블에 적기만 하고 중계 잡이 RabbitMQ 로 넘기고 워커가 inbox(message_id 선점)로 한 번만 보내는 구조로 바꿨다. 구간마다 at-least-once 와 at-most-once 를 다르게 고른 이유와 장애 지점별 동작을 정리했다.

· 16분 읽기

PG 를 바꾸며 돈과 주문을 맞추는 법 – 아임포트(KCP)에서 토스페이먼츠 직접 연동으로

아임포트를 거쳐 KCP 로 결제하던 구조를 토스페이먼츠 직접 연동으로 바꾼 기록이다. 두 PG 의 결제건이 함께 살아 있던 전환 기간의 설계, 트랜잭션 없이 돈과 주문을 맞춘 장치, 승인 후 취소가 생기는 재고 구조, 무통장입금 만료가 석 달 반 동안 처리되지 않았던 사고를 정리했다.

· 14분 읽기

한 주문에 문이 세 개 – 결제 완료 API·PG 웹훅·취소를 주문번호 분산락 하나로 줄 세우기

토스페이먼츠 결제 흐름을 새로 만들면서 같은 주문에 결제 완료 API, PG 웹훅, 취소가 거의 같은 순간에 들어올 수 있다는 것을 보고 처음부터 주문번호 분산락을 설계했다. 락이 없으면 어떤 경합이 생기는지, 락 키가 주문번호여야 했던 이유, 대기·임대·소유자 id 의 세부, 락 뒤에 겹쳐 둔 장치, 다른 대안과 그것을 바깥 문으로 쓰지 않는 이유를 정리했다.

· 15분 읽기

먼저 ack 하던 알림 소비자 – 코루틴 launch 가 메시지를 잃는 이유와 처리 후 ack·멱등 처리

RabbitMQ 알림 리스너가 CoroutineScope.launch 로 일을 넘기고 바로 반환해, 알림을 보내기 전에 ack 가 나가던 문제를 정리했다. runBlocking 으로 처리 후 ack 하도록 바꾸고, 그로 인해 생기는 재배달을 수신 원장과 업무 키로 막았다.

· 16분 읽기