Engineering

Next.js 웹훅 멱등성 설계: 중복 결제와 중복 처리 사고를 막는 실전 운영법

Mike발행일 2026년 2월 26일수정일 2026년 2월 27일읽는 시간 약 1

💡 Key Takeaways

  • 멱등성은 if 문이 아니라 DB 유니크 키와 상태 전이 규칙으로 완성됩니다.
  • 이벤트 수신 즉시 로그 저장을 먼저 해야 장애 분석과 재처리가 쉬워집니다.
  • 중복 이벤트는 200으로 응답해 재전송 폭주를 막아야 합니다.
  • 동시 2회 유입, 순서 역전 유입 테스트를 CI에 넣어야 사고를 줄일 수 있습니다.

Next.js 웹훅 멱등성 설계: 중복 결제와 중복 처리 사고를 막는 실전 운영법

웹훅 연동은 "한 번 오겠지"라고 생각하는 순간부터 위험합니다. 실제 운영에서는 타임아웃, 재시도, 네트워크 지연으로 같은 이벤트가 두 번 이상 들어오는 게 정상입니다. 중복 처리 사고는 대체로 코드 복잡도 때문이 아니라 처리 순서를 명확히 정하지 않아서 생깁니다.

1) 중복 판정 키부터 고정

현장에서 가장 안전했던 조합은 아래 3개입니다.

  • provider_event_id (공급자 고유 ID)
  • event_type (예: payment.succeeded)
  • resource_id (우리 주문/구독 ID)

이 3개를 유니크 인덱스로 묶으면 "무엇이 중복인지"가 코드가 아니라 스키마에 박힙니다.

2) 처리 순서 (이 순서가 핵심)

  1. 서명 검증
  2. 원본 페이로드 저장
  3. 유니크 인덱스로 중복 판정
  4. 상태 전이 검증 (pending -> paid -> refunded 같은 규칙)
  5. 도메인 반영
  6. 처리 결과 기록

중복으로 판정되면 에러를 내지 말고 200으로 끝내는 게 좋습니다. 그래야 공급자 재시도가 줄고 운영 소음도 줄어듭니다.

3) Next.js 최소 흐름 예시

// app/api/webhooks/provider/route.ts
const inserted = await insertWebhookEvent(eventKey)
if (!inserted) {
  return NextResponse.json({ ok: true, duplicate: true })
}

await applyDomainTransitionOrThrow(payload)
await markWebhookHandled(eventKey)
return NextResponse.json({ ok: true })

핵심은 "처리 전 기록"입니다. 나중에 "왜 중복 처리됐는지"를 추적할 수 있어야 합니다.

4) 운영 체크리스트

  • 최근 1시간 중복 유입 비율
  • 서명 검증 실패율
  • 상태 전이 거부 건수
  • 수동 재처리 큐 적체량

배포 전에 동시 2회 유입 테스트와 순서 역전 테스트를 돌리면 대부분의 큰 사고를 미리 잡을 수 있습니다.

함께 읽으면 좋은 글

Engineering

Next.js 인증 리다이렉트 루프 방지 플레이북: 로그인 UX와 보안을 동시에 지키는 운영 설계

2026-03-03
Engineering

Next.js 서버 액션 장애 복구 플레이북: 실패를 사용자 이탈로 번지지 않게 막는 실무 설계

2026-03-01

본문 작성/검수 원칙은 편집 원칙에서 확인할 수 있습니다.

← 목록으로 돌아가기