사이드프로젝트 slecs

결제 외부 연동 재시도 개선과 수령 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

첫 댓글 달아줘.