재전송과 멱등성
페이리는 200을 받지 못하면 정해진 간격으로 재전송해요.
그래서 같은 이벤트가 여러 번 도착할 수 있어요.
수신 측은 중복이 와도 한 번만 처리되도록 멱등하게 구현해야 해요.
재시도 규칙
발송은 최대 5회예요.
첫 발송 후 실패하면 아래 간격으로 재시도하고, 5회째도 실패하면 failed로 종료해요.
| 시도 | 직전 실패 후 대기 |
|---|---|
| 1회차 | 즉시 |
| 2회차 | 1분 |
| 3회차 | 5분 |
| 4회차 | 15분 |
| 5회차 | 60분 |
성공 판정은 HTTP 200뿐이에요.
그 외 상태·10초 타임아웃·네트워크 오류는 실패로 보고 재시도해요.
발송 이력은 셀러 콘솔에서 pending·delivered·failed로 확인할 수 있어요.
멱등 처리
재전송된 요청은 본문과 헤더가 처음과 완전히 똑같아요.
특히 webhook-id 헤더는 최초 발송 때 정해져 재전송에도 그대로 유지되므로, 이 값을 멱등 키로 쓰면 돼요.
처리 전에 이 키를 저장소에 기록하고, 이미 있으면 그냥 200만 돌려주세요.
const idempotencyKey = req.get('webhook-id') // msg_... — 재전송에도 동일
if (await store.seen(idempotencyKey)) return res.sendStatus(200) // 이미 처리
await store.markSeen(idempotencyKey)
// ... 실제 처리 ...
res.sendStatus(200)같은 사건이라도 발송 건이 다르면 webhook-id도 달라요.
비즈니스 수준의 중복(예: 같은 주문의 order.paid를 두 번 반영)까지 막으려면
본문의 리소스 식별자(data.id·data.subscriptionId)와 type 조합으로 한 번 더 확인하세요.
무거운 작업(이메일 발송·외부 API 호출 등)은 큐로 넘기고 먼저 200을 응답하세요.
처리에 10초 넘게 걸리면 타임아웃으로 실패 처리돼 불필요한 재전송이 생겨요.
Last updated on