결제 외부 연동 재시도 개선과 수령 ID 분리로 추적 안정화
목차
v3.1 작업 회고 — 재시도 로직 갈아엎고 메시지 ID 분리
오랜만에 결제 플랫폼 외부 연동 모듈 손봤음. 외부 API 호출 실패율이 새벽 시간대에 튀는 문제랑, 수령 결과 응답에서 메시지 ID 구분이 안 돼서 추적 안 되던 이슈 두 개를 한 번에 처리.
재시도 로직, 뭐가 문제였나
기존 API 클라이언트의 재시도가 너무 단순했음. 고정 간격 3회 + 무조건 재시도 — 이게 두 가지를 다 망치고 있었음.
- 4xx 응답까지 재시도 → 잘못된 요청을 3번 더 때리고 똑같이 실패
- 새벽 피크 때 외부 측이 5초 throttle 걸면 우리가 1초 간격으로 3번 때리고 다 죽음
- 재시도 대기 시간 동안 커넥션이 풀에 묶여서 다른 호출까지 도미노
| 항목 | Before | After |
|---|---|---|
| 재시도 트리거 | 모든 예외 | 5xx + 타임아웃 + 커넥션 에러만 |
| 백오프 | 1초 고정 × 3 | 지수 백오프 + jitter (0.5~3.5s) |
| 최대 시도 | 4회 | 3회 (감소) |
| 4xx 처리 | 재시도 | 즉시 fail-fast |
지수 백오프에 jitter 안 넣으면 동시에 죽은 요청이 동시에 깨어나서 또 같이 죽는다는 걸 한 번 더 확인. 교과서 그대로지만 직접 그래프로 보니까 새삼.
attempt=1 delay=0 status=503
attempt=2 delay=820 status=503
attempt=3 delay=2150 status=200 ← 살아남음
지표상 5xx 재시도 성공률이 18% → 41% 로 올라왔고, 4xx fail-fast 덕에 평균 응답 시간도 같이 떨어짐. 의외의 보너스.
메시지 ID 구분 — 추적 안 되던 이유
메신저 플랫폼 수령 결과 콜백을 받는 모듈에서, 발송 ID랑 수령 결과 ID를 같은 필드로 쓰고 있었음. 발송할 때 발급한 ID가 그대로 결과로 돌아오는 줄 알았는데, 실제로는 외부 측이 결과 단계에서 새 ID를 따로 발급하더라.
dispatchId: 우리가 보낼 때 외부에 넣어주는 발송 식별자receiveResultId: 외부가 결과 단계에서 새로 만들어 돌려주는 ID- 둘을 같은 컬럼에 우겨넣어서, 실패 케이스 추적할 때 어느 쪽을 본 건지 분간 불가
수령 처리 서비스에서 두 ID를 분리해서 저장하도록 스키마 + 매핑 둘 다 손봤음. 마이그레이션은 기존 행은 발송 ID 로 간주하고 결과 ID 컬럼은 NULL 로 두는 식. 신규 데이터부터 양쪽 다 채워짐.
배운 것
- 재시도는 무엇을 재시도하지 않을지 정하는 게 더 중요. 4xx 빼는 것만으로 절반은 해결.
- 외부 시스템이 단계별로 별도 ID 를 발급할 가능성을 처음부터 의심해야 함. "같은 ID 겠지" 가정은 거의 항상 틀림.
- 운영 지표 보면서 수치로 확인하니까 PR 리뷰 설득력도 같이 올라감.
다음
댓글 0
첫 댓글 달아줘.