
2026년 9월 2일4분 분량Администратор
승인 후 타임아웃: 멱등성 보호는 어디까지인가
API 키를 실제 업무 거래와 연결하고, 타임아웃을 견디고, 요청 재시도가 새로운 출금이 되지 않게 하는 방법.
결제 API에서 가장 비싼 응답은 때로 응답이 없는 모습으로 나타납니다. 서버가 결과를 기다리지 못했다고 해서 PG사가 출금을 실행했는지 여부를 알 수 있는 것은 아닙니다. 무작위로 만든 새 멱등성 키는 새로운 HTTP 응답을 받게 해 주지만, 동시에 두 번째 거래를 만들 수도 있습니다. 재시도를 안전하게 하려면 먼저 무엇이 '같은 것'으로 남는지 합의해야 합니다.
직원 두 명이 같은 환불을 처리한다
더 조용한 오류를 상상해 봅시다. 고객 지원팀이 20유로를 환불하고, 재무 담당자도 거의 동시에 같은 문의 건으로 20유로를 또 환불합니다. API 키는 서로 다르고, 두 요청 모두 기술적으로는 올바릅니다. 이 경우 PG사의 멱등성 처리는 두 직원이 하나의 지시를 수행하고 있다는 사실을 알아채지 못합니다. 보호는 내부 환불 건과 그 실행에 대한 고유한 승인에서 시작되어야 합니다.
합의된 환불은 PG사에 요청하기 전에 기록부터 만드십시오. 이 기록은 고객 문의, 원거래, 금액, 사유를 연결합니다. 두 번째 직원은 새 항목을 만드는 대신 이미 생성된 작업을 보게 되어야 합니다. 한편 실제로 별개인 부분 환불 두 건은 정당합니다. 예를 들어 반품된 상품이 두 개인 경우입니다. 시스템은 지시의 반복과 새로운 지시를 구분해야 하므로, 금액 하나를 비교하는 것만으로는 부족합니다.
거래 하나를 정의하는 것부터 시작하라
제안하는 모델은 주문 번호와 결제에 대한 작업 번호를 분리합니다. 주문 하나에는 승인, 허용된 여러 번의 부분 매입, 별도의 환불이 포함될 수 있습니다. 그래서 '주문 번호'는 모든 요청에 쓰기에는 너무 넓고, HTTP 호출마다 새로 만드는 무작위 키는 너무 좁습니다. 먼저 구체적인 작업에 대한 안정적인 내부 기록을 만드십시오.
예를 들어 가상의 주문 Q-731은 48유로 매입을 예정하고 있습니다. 내부 비즈니스 키는 'Q-731, 매입, 1회차'를 뜻합니다. 여기에 금액, 통화, 수취인, PG사 계정, 의도의 버전이 연결됩니다. API 호출을 위해서는 별도의 불투명한 키를 생성하고, 첫 전송 전에 저장합니다. 중복 클릭, 백그라운드 프로세스, 장애에서 복구된 서버 모두 이 같은 키를 사용합니다. 여기에 개인정보를 넣을 필요는 없습니다.
멱등성 요청에 관한 Stripe 문서는 API 버전을 고려하는 것이 왜 중요한지 보여 줍니다. API v1에서는 실행이 시작된 뒤의 재시도가 일부 오류 응답을 포함해 저장된 결과를 반환합니다. 키의 보관 기간과 파라미터 비교 규칙도 계약의 일부입니다. 어떤 키든 반복 거래를 영구히 막아 준다고 여기지 마십시오.
'결과 미확정' 상태는 명시적이어야 한다
- 1.준비됨. 플랫폼이 작업, 그 파라미터, PG사용 키를 저장했습니다. 유일성 제약 덕분에 두 핸들러가 같은 의도를 각자 따로 만들 수 없습니다.
- 2.전송됨. 실행자 한 명이 요청을 실행할 권한을 얻었고, 나머지는 기존 거래를 보며 새 거래를 만들지 않습니다.
- 3.결과 미확정. 응답이 유실되었거나 불충분합니다. 이것은 별도의 업무 상태이지, 자동으로 확인된 거절이 아닙니다.
- 4.결과 확정. 응답, 검증된 이벤트, 또는 정해진 대사가 결과를 확인해 줍니다. 플랫폼은 이를 기록하고 정해진 비즈니스 조치를 실행합니다.
여기서 상태 이름은 예시입니다. 실제 시스템에서는 승인, 매입, 취소 등 여러 단계를 구분해야 할 것입니다. 중요한 것은 따로 있습니다. 팀이 미완료 상태를 볼 수 있어야 하고, 이를 해소하는 허용된 방법을 알아야 합니다. '최신' 응답을 받겠다고 미확정 상태를 새 키로 덮지 마십시오.
정확히 무엇을 재시도할 수 있는가
재시도하기 전에 같은 거래인지, 중요한 파라미터가 같은지, PG사의 규칙 범위 안인지 확인하십시오. PayPal에서는 PayPal-Request-Id 지원과 보관 기간이 API마다 다릅니다. 재시도하면 이전 요청의 현재 상태가 반환될 수 있습니다. 모든 결제 SDK가 똑같이 동작한다고 가정하지 말고 해당 메서드의 계약을 확인해야 하는 또 하나의 이유입니다.
고객이 주문 구성을 바꿔 금액이 53유로가 되었다면, 이는 결제에 대한 새로운 결정이 필요한 상황입니다. 먼저 이전 48유로 작업이 어떻게 되었는지 확인하십시오. 그다음에야 제품 프로세스와 고객 동의에 따라 취소, 추가 결제, 새 거래 중 무엇이 필요한지 정합니다. 재시도 요청에서 금액만 바꿔치기하면 비즈니스 의도의 중요한 변화가 가려집니다.
자체 서비스에서는 중요한 파라미터의 지문을 저장하고, 같은 내부 키로 들어온 상충하는 요청을 거부하는 것이 유용합니다. 어떤 필드가 중요한지 미리 정하십시오. 금액과 수취인은 반드시 주의가 필요하지만, 기술적인 트레이스 식별자는 보통 결제의 의미를 바꾸지 않습니다. 비밀값이나 전체 결제 정보를 드러내지 않으면서 고객 지원팀에 충돌에 대한 명확한 메시지를 제공하십시오.
보호의 경계는 API 계약을 따라 그어진다
Adyen은 키의 적용 범위를 따로 설명하며, 일부 지역별 엔드포인트 사이에는 공통 중복 검사가 없다는 점도 밝힙니다. 따라서 요청을 다른 경로로 옮긴 것을 자동으로 같은 보호를 받는 재시도로 볼 수 없습니다. 하물며 독립된 두 PG사에서 키 문자열이 같다고 해서 그 자체로 공통 조율이 생기지는 않습니다.
내부 이력은 네트워크 요청의 수명보다 길게 보관하고, 오래된 미해결 거래를 처리하는 절차를 정하십시오. PG사가 보장하는 기간이 끝난 뒤에는 먼저 대사가 필요합니다. 결과를 확정할 수 없다면 끝없는 재시도 대신 예외 건 담당자와 에스컬레이션 경로를 지정하십시오.
수동 수정을 숨기지 마라
운영자에게는 멈춘 작업의 잠금을 푸는 편이 대사를 기다리는 것보다 편할 때가 있습니다. 이런 전환은 눈에 띄게 만드십시오. 누가 진행을 승인했는지, 어떤 증거가 이전 결과를 확인했는지, 어떤 새 거래가 이전 거래를 대체하는지입니다. 데이터베이스에서 상태만 슬쩍 고치면 인과 관계가 사라지고, 다음 근무조에는 그럴듯하지만 틀린 이력이 남습니다.
설계 리뷰에서 쓸 만한 방법이 있습니다. 작업을 실행할 수 있는 모든 지점을 나열하는 것입니다. 구매자의 버튼, 스케줄 작업, SDK 재시도, 고객 지원 콘솔, 대기열 복구, 수동 스크립트가 모두 하나의 의도 모델 안에 있어야 합니다. 그렇지 않으면 각 컴포넌트는 자기 중복은 올바르게 막겠지만, 시스템 전체로는 계속 다른 곳의 중복을 만들어 냅니다.
다음 연동 리뷰는 가장 단순한 질문으로 시작하십시오. 환불이나 매입에 대한 승인된 지시는 어디에 저장되어 있는가? 답이 HTTP 요청 안의 키뿐이라면, 보호는 너무 늦게 시작되는 것입니다.
댓글 · 0
아직 댓글이 없습니다 — 첫 댓글을 남겨 보세요.
로그인 · 댓글을 남기려면 로그인하세요.