Skip to content

Latest commit

ย 

History

History
174 lines (141 loc) ยท 15.7 KB

README.md

File metadata and controls

174 lines (141 loc) ยท 15.7 KB

๊ฒฐ์ œ

๋„๋ฉ”์ธ

  • ์Šน๊ฐ์€ ์˜ˆ์•ฝ์„ ๊ณ ๋ฅธ ๋’ค ๊ฒฐ์ œ ์ค€๋น„ โ†’ ๊ฒฐ์ œ์ฐฝ โ†’ ๊ฒฐ์ œ ์Šน์ธ ์ˆœ์œผ๋กœ ๊ฒฐ์ œํ•œ๋‹ค. ๊ฒฐ์ œ์‚ฌ๋Š” ํ† ์ŠคํŽ˜์ด๋จผ์ธ (Toss)๋‹ค.
  • ๊ฒฐ์ œ ์ค€๋น„
    • ๊ณ ๋ฅธ ์˜ˆ์•ฝ์ด ๋ชจ๋‘ ์ž๊ธฐ ๊ฒƒ์ด๊ณ  ์‚ด์•„ ์žˆ๋Š”์ง€, ์ด๋ฏธ ํŒ”๋ฆฐ ์ขŒ์„๊ณผ ๊ฒน์น˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • ์ฃผ๋ฌธ๊ณผ ๊ฒฐ์ œ๋ฅผ ๊ฒฐ์ œ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ์ฃผ๋ฌธ ์ฝ”๋“œ์™€ ๊ธˆ์•ก์„ ๋Œ๋ ค์ค€๋‹ค.
  • ๊ฒฐ์ œ์ฐฝ: ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๋ฌธ ์ฝ”๋“œ์™€ ๊ธˆ์•ก์œผ๋กœ Toss ๊ฒฐ์ œ์ฐฝ์„ ์—ฐ๋‹ค. ์Šน๊ฐ์ด ๊ฒฐ์ œํ•˜๋ฉด Toss๊ฐ€ paymentKey๋ฅผ ์ค€๋‹ค.
  • ๊ฒฐ์ œ ์Šน์ธ
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ paymentKey, ์ฃผ๋ฌธ ์ฝ”๋“œ, ๊ธˆ์•ก์„ ๋ณด๋‚ด๋ฉด ์„œ๋ฒ„๊ฐ€ Toss์— ์Šน์ธ์„ ์š”์ฒญํ•œ๋‹ค.
    • ์Šน์ธ๋˜๋ฉด ์ฃผ๋ฌธ์ด ์™„๋ฃŒ๋˜๊ณ  ์˜ˆ๋งค์™€ ์Šน์ฐจ๊ถŒ์ด ๋งŒ๋“ค์–ด์ง„๋‹ค.
    • ์ขŒ์„ ์ ์œ ๋ฅผ ์˜ˆ์•ฝ์—์„œ ์˜ˆ๋งค๋กœ ๋ฐ”๊พธ๋Š” ์ผ์€ ์ž ์‹œ ๋’ค Outbox Worker๊ฐ€ ํ•œ๋‹ค.
  • ์Šน์ธ ์š”์ฒญ์€ ๊ฐ™์€ ๊ฒฐ์ œ์— ์—ฌ๋Ÿฌ ๋ฒˆ ์˜ฌ ์ˆ˜ ์žˆ๋‹ค(์ƒˆ๋กœ๊ณ ์นจ, ์žฌ์‹œ๋„). ์นด๋“œ๋Š” ํ•œ ๋ฒˆ๋งŒ ์ฒญ๊ตฌ๋ผ์•ผ ํ•˜๊ณ  ์˜ˆ๋งค๋„ ํ•œ ๋ฒˆ๋งŒ ๋งŒ๋“ค์–ด์ ธ์•ผ ํ•œ๋‹ค.
  • Toss๊ฐ€ ์Šน์ธํ–ˆ๋Š”์ง€ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค(ํƒ€์ž„์•„์›ƒ, Toss 5xx). ์ด๋•Œ๋Š” ์‹คํŒจ๋กœ ๋‹จ์ •ํ•˜์ง€ ์•Š๊ณ , ์Šน๊ฐ์ด ๋‹ค์‹œ ์š”์ฒญํ•˜๋ฉด Toss์— ์ƒํƒœ๋ฅผ ์กฐํšŒํ•ด ๋งž์ถ˜๋‹ค. ๊ทธ ์‚ฌ์ด ์˜ˆ์•ฝ TTL์ด ์ขŒ์„์„ ๊ฐ€์ ธ๊ฐ€์ง€ ์•Š๋„๋ก ์ขŒ์„์„ ๋ถ™์žก์•„ ๋‘”๋‹ค.

์šฉ์–ด

ํ•œ๊ตญ์–ด ์˜์–ด ์„ค๋ช…
๊ฒฐ์ œ Payment ์ฃผ๋ฌธ ํ•˜๋‚˜์— ๋Œ€ํ•œ ๊ฒฐ์ œ. ๊ธˆ์•ก๊ณผ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค
๊ฒฐ์ œ ์‹œ๋„ PaymentAttempt Toss์— ๋ณด๋‚ด๋Š” ์Šน์ธ ์š”์ฒญ ํ•˜๋‚˜์˜ ๊ธฐ๋ก. ๊ฐ™์€ ์š”์ฒญ์˜ ์žฌ์‹œ๋„๋Š” ๊ฐ™์€ ์‹œ๋„๋‹ค
์‹œ๋„ ID attemptId ์‹œ๋„๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ์™ธ๋ถ€ ๋ฉฑ๋“ฑ ํ‚ค. paymentKey์—์„œ ๊ณ„์‚ฐํ•œ๋‹ค
paymentKey - Toss๊ฐ€ ๊ฒฐ์ œ์ฐฝ์—์„œ ๋ฐœ๊ธ‰ํ•œ ๊ฒฐ์ œ ์‹๋ณ„์ž
์ฃผ๋ฌธ ์ฝ”๋“œ orderCode Toss์— ๋„˜๊ธฐ๋Š” ์ฃผ๋ฌธ ๋ฒˆํ˜ธ(orderId). ์ฃผ๋ฌธ์˜ ์ฃผ๋ฌธ ์ฝ”๋“œ์™€ ๊ฐ™๋‹ค
ํ™•์ • ๋Œ€์ƒ PaymentConfirmTarget ํ™•์ •ํ•  ๊ฒฐ์ œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์„ธ ๊ฐ’(paymentKey, ์ฃผ๋ฌธ ์ฝ”๋“œ, ๊ธˆ์•ก). DB์—์„œ ์ฝ๋Š”๋‹ค
๊ฒฐ๊ณผ ๋ถˆ๋ช… - ์š”์ฒญ์€ ๋‚˜๊ฐ”์ง€๋งŒ Toss๊ฐ€ ์Šน์ธํ–ˆ๋Š”์ง€ ๋ชจ๋ฅด๋Š” ์‹คํŒจ
๋ฏธ์ „์†ก NOT_SENT ์š”์ฒญ์ด Toss์— ๋„๋‹ฌํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด ํ™•์ •์ธ ์‹คํŒจ
TX A, TX B - ์Šน์ธ ์‹œ์ž‘ ํŠธ๋žœ์žญ์…˜๊ณผ ์Šน์ธ ํ™•์ • ํŠธ๋žœ์žญ์…˜

๋„๋ฉ”์ธ ๋ชจ๋ธ

classDiagram
    Payment --> Order
    Payment --> Member
    Payment "1" <-- "N" PaymentAttempt : paymentId
    Payment "1" <-- "N" PaymentOutbox : aggregateId
Loading

[๊ฒฐ์ œ]

๊ฒฐ์ œ(Payment)

Aggregate Root

  • ์†์„ฑ: member, order, orderCode, amount, paymentStatus, paymentKey, paymentMethod, paidAt, failedAt, cancelledAt, refundedAt, failureCode, failureMessage
  • ํ–‰์œ„
    • static create(member, order): ์ฃผ๋ฌธ์˜ ์ฝ”๋“œ์™€ ๊ธˆ์•ก์œผ๋กœ ๊ฒฐ์ œ ๋Œ€๊ธฐ ๊ฒฐ์ œ๋ฅผ ๋งŒ๋“ ๋‹ค
    • approve(method, paymentKey): ๊ฒฐ์ œ ์™„๋ฃŒ. Toss๊ฐ€ ๋ฐœ๊ธ‰ํ•œ paymentKey๋ฅผ ์ €์žฅํ•œ๋‹ค
    • cancel(reason), refund(), fail(code, message)
  • ๊ทœ์น™
    • ๊ฒฐ์ œ ๋Œ€๊ธฐ์—์„œ๋งŒ ์Šน์ธ, ์ทจ์†Œ, ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ์ œ ์™„๋ฃŒ์—์„œ๋งŒ ํ™˜๋ถˆํ•  ์ˆ˜ ์žˆ๋‹ค
    • ๊ฐ™์€ ์ฃผ๋ฌธ์— ๊ฒฐ์ œ ์™„๋ฃŒ๋œ ๊ฒฐ์ œ๊ฐ€ ์žˆ์œผ๋ฉด ์Šน์ธํ•˜์ง€ ์•Š๋Š”๋‹ค
    • member, order๋Š” DB ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฑธ์ง€ ์•Š๋Š”๋‹ค
    • cancel, refund, fail์„ ๋ถ€๋ฅด๋Š” ๊ณณ์€ ์•„์ง ์—†๋‹ค. Toss๊ฐ€ ์Šน์ธ์„ ๊ฑฐ์ ˆํ•ด๋„ ๊ฒฐ์ œ๋Š” ๊ฒฐ์ œ ๋Œ€๊ธฐ๋กœ ๋‚จ๊ณ  ์‹œ๋„๋งŒ ์‹คํŒจ๊ฐ€ ๋œ๋‹ค

๊ฒฐ์ œ ์ƒํƒœ(PaymentStatus)

Enum: PENDING ๊ฒฐ์ œ ๋Œ€๊ธฐ, PAID ๊ฒฐ์ œ ์™„๋ฃŒ, CANCELLED ๊ฒฐ์ œ ์ทจ์†Œ, REFUNDED ํ™˜๋ถˆ ์™„๋ฃŒ, FAILED ๊ฒฐ์ œ ์‹คํŒจ

๊ฒฐ์ œ ์‹œ๋„(PaymentAttempt)

Entity, Payment N:1 (์™ธ๋ž˜ํ‚ค ์—†์ด paymentId)

  • ์†์„ฑ: attemptId, attemptType, status, paymentKey, errorCode, errorMessage
  • ํ–‰์œ„
    • static startApproval(paymentId, attemptId, paymentKey): ์ง„ํ–‰ ์ค‘ ์Šน์ธ ์‹œ๋„๋ฅผ ๋งŒ๋“ ๋‹ค
    • markSucceeded(), markFailed(...), markNotSent(...), markReviewRequired(...): ์ง„ํ–‰ ์ค‘์—์„œ๋งŒ ๋ฐ”๋€๋‹ค
    • reopen(): ๋ฏธ์ „์†ก์„ ๋‹ค์‹œ ์ง„ํ–‰ ์ค‘์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค
  • ๊ทœ์น™
    • attemptId๋Š” sha256("apv:" + paymentKey)๋‹ค. ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ์œ ๋‹ˆํฌ ์ œ์•ฝ์ด ์žˆ๋‹ค
    • ์‹œ๋„์˜ paymentKey์™€ ๊ฒฐ์ œ, ์œ ํ˜•์ด ์š”์ฒญ๊ณผ ๋‹ค๋ฅด๋ฉด ๊ฐ™์€ ์˜ค๋ฅ˜(PAYMENT_ATTEMPT_REQUEST_MISMATCH)๋กœ ๊ฑฐ์ ˆํ•œ๋‹ค. ์–ด๋А ์ชฝ์ด ๋‹ค๋ฅธ์ง€๋Š” ๋กœ๊ทธ์—๋งŒ ๋‚จ๊ธด๋‹ค
    • ์š”์ฒญ๊ณผ์˜ ๋Œ€์กฐ๋Š” ์ž ๊ธˆ ์—†๋Š” ์‹œ์ž‘ ๋‹จ๊ณ„์—์„œ ํ•œ๋‹ค. ํ™•์ •(TX B)์€ ์ €์žฅ๋œ ๊ฐ’์œผ๋กœ ๋น„๊ตํ•˜๋ฏ€๋กœ paymentKey ์ถ•์ด ํ•ญ์ƒ ์ผ์น˜ํ•œ๋‹ค. ์š”์ฒญ์˜ paymentKey๋Š” attemptId ํŒŒ์ƒ๊ณผ ์œ ๋‹ˆํฌ ์ œ์•ฝ์œผ๋กœ ์ด๋ฏธ ์‹œ๋„์— ๋ฌถ์—ฌ ์žˆ๋‹ค
    • processingOwner, processingLeaseUntil, nextRetryAt์€ ๋ณต๊ตฌ Worker๊ฐ€ ์„ ์ ๊ณผ ๋ฐฑ์˜คํ”„์— ์“ด๋‹ค

์‹œ๋„ ์ƒํƒœ(PaymentAttemptStatus)

Enum

์ƒํƒœ ๋œป ๊ฐ™์€ ์‹œ๋„๋กœ ๋‹ค์‹œ ์Šน์ธ ์š”์ฒญ์ด ์˜ค๋ฉด
IN_PROGRESS Toss ํ˜ธ์ถœ ์ „์ด๊ฑฐ๋‚˜ ๊ฒฐ๊ณผ ๋ถˆ๋ช… Toss์— ์ƒํƒœ๋ฅผ ์กฐํšŒํ•ด ๋งž์ถ˜๋‹ค(PaymentApprovalReconciler)
SUCCEEDED ์Šน์ธ ํ™•์ • Toss ํ˜ธ์ถœ ์—†์ด ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค์ค€๋‹ค
FAILED Toss๊ฐ€ ๊ฑฐ์ ˆ ๊ฑฐ์ ˆํ•œ๋‹ค
NOT_SENT ์š”์ฒญ์ด Toss์— ๋„๋‹ฌํ•˜์ง€ ์•Š์Œ ๊ฐ™์€ ์‹œ๋„๋ฅผ ๋‹ค์‹œ ์ง„ํ–‰ ์ค‘์œผ๋กœ ์—ด๊ณ  ์Šน์ธ์„ ๋‹ค์‹œ ๋ณด๋‚ธ๋‹ค
REVIEW_REQUIRED ์Šน์ธ๋์„ ์ˆ˜ ์žˆ์–ด ์ž๋™ ํ™•์ •ํ•˜๋ฉด ์•ˆ ๋จ ๊ฑฐ์ ˆํ•˜๊ณ  ๊ณ ๊ฐ์„ผํ„ฐ๋กœ ์•ˆ๋‚ดํ•œ๋‹ค

REVIEW_REQUIRED๋Š” ์ข…์ฐฉ์ ์ด๋‹ค. ๋‚˜๊ฐ€๋Š” ์ „์ด๊ฐ€ ์—†์–ด ์ž๋™์œผ๋กœ ๋˜์‚ด์•„๋‚˜์ง€ ์•Š๋Š”๋‹ค. ์‚ฌ์œ ๋Š” errorCode์— ๋‚จ๋Š”๋‹ค.

์‚ฌ์œ  ์–ธ์ œ
REVIEW_RESULT_MISMATCH Toss ์กฐํšŒ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋œ ์ฃผ๋ฌธ ์ฝ”๋“œ, ๊ธˆ์•ก, paymentKey์™€ ๋‹ค๋ฅด๋‹ค
REVIEW_PAYMENT_KEY_MISSING ์‹œ๋„์— paymentKey๊ฐ€ ์—†์–ด ์กฐํšŒ์กฐ์ฐจ ๋ชป ํ•œ๋‹ค
REVIEW_SEAT_LOST ํ™•์ • ๋‹จ๊ณ„์—์„œ ์ขŒ์„์ด ์ด๋ฏธ ๋‹ค๋ฅธ ์˜ˆ๋งค์˜ ๊ฒƒ์ด๋‹ค
REVIEW_DEPARTED ํ™•์ • ๋‹จ๊ณ„์—์„œ ์ถœ๋ฐœ ์‹œ๊ฐ์ด ์ง€๋‚ฌ๋‹ค
REVIEW_RECOVERY_TIMEOUT ๋ณต๊ตฌ Worker๊ฐ€ ์ตœ๋Œ€ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ๋„˜๊ธฐ๋„๋ก ํŒ์ •ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค

PaymentAttemptType์€ APPROVAL, CANCELLATION์ด๋‹ค. ์ทจ์†Œ ์‹œ๋„๋Š” ์•„์ง ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

๋„๋ฉ”์ธ ์„œ๋น„์Šค

๊ฒฐ์ œ ์Šน์ธ(PaymentConfirmService)

confirm์€ ํŠธ๋žœ์žญ์…˜์„ ์—ด์ง€ ์•Š๊ณ  ์„ธ ๋‹จ๊ณ„๋ฅผ ์ž‡๋Š”๋‹ค.

  1. ์‹œ์ž‘ (PaymentApprovalStarter, PaymentAttemptManager)
    • ์ฃผ๋ฌธ, ๊ฒฐ์ œ ์†Œ์œ ์ž์™€ ๊ธˆ์•ก(์š”์ฒญ = ์ฃผ๋ฌธ = ๊ฒฐ์ œ)์„ ํ™•์ธํ•œ๋‹ค.
    • ๊ฐ™์€ attemptId์˜ ์‹œ๋„๊ฐ€ ์žˆ์œผ๋ฉด ์œ„ ํ‘œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ง„ํ–‰ ์ค‘์ด๋ฉด PaymentApprovalReconciler๊ฐ€ Toss๋ฅผ ์กฐํšŒํ•ด ํŒ์ •ํ•œ๋‹ค.
    • ์—†์œผ๋ฉด ๊ฒฐ์ œ ๋Œ€๊ธฐ์ธ์ง€, ์˜ˆ์•ฝ์ด ์‚ด์•„ ์žˆ๋Š”์ง€, ๊ฐ™์€ ์ฃผ๋ฌธ์— ์™„๋ฃŒ๋œ ๊ฒฐ์ œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • TX A์—์„œ ๊ฒฐ์ œ๋ฅผ ์ž ๊ทธ๊ณ  ๋‹ค์‹œ ํ™•์ธํ•œ ๋’ค ์ง„ํ–‰ ์ค‘ ์‹œ๋„๋ฅผ ์ปค๋ฐ‹ํ•œ๋‹ค.
  2. Toss ์Šน์ธ ํ˜ธ์ถœ: DB ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ ํ•œ๋‹ค.
    • ๊ฑฐ์ ˆ(4xx)์ด๋ฉด ์‹œ๋„๋ฅผ ์‹คํŒจ๋กœ ๋ฐ”๊พธ๊ณ  ์ขŒ์„ ๋ณดํ˜ธ๋ฅผ ํ‘ผ๋‹ค.
    • ๋ฏธ์ „์†ก์ด๋ฉด ์‹œ๋„๋ฅผ ๋ฏธ์ „์†ก์œผ๋กœ ๋ฐ”๊พผ๋‹ค.
    • ๊ฒฐ๊ณผ ๋ถˆ๋ช…์ด๋ฉด ์ง„ํ–‰ ์ค‘์œผ๋กœ ๋‘๊ณ  ์ขŒ์„์„ ๋ถ™์žก๋Š”๋‹ค.
  3. ํ™•์ • (PaymentApprovalFinalizer, TX B)
    • ๊ฒฐ์ œ๋ฅผ ์ž ๊ทธ๊ณ  ์‹œ๋„ ์ƒํƒœ๋ฅผ ๋‹ค์‹œ ๋ณธ๋‹ค.
    • Toss ์‘๋‹ต์˜ ๊ธˆ์•ก, paymentKey, ์ฃผ๋ฌธ ์ฝ”๋“œ๊ฐ€ DB์— ์ €์žฅ๋œ ๊ฐ’๊ณผ ๊ฐ™์€์ง€ ํ™•์ธํ•œ๋‹ค. ์š”์ฒญ์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
    • ์ถœ๋ฐœ ์‹œ๊ฐ์ด ์ง€๋‚ฌ๋Š”์ง€, ์ขŒ์„์ด ๋‹ค๋ฅธ ์˜ˆ๋งค์˜ ๊ฒƒ์ด ๋๋Š”์ง€ ์ž ๊ธˆ ์•„๋ž˜์—์„œ ๋‹ค์‹œ ๋ณธ๋‹ค.
    • ์ฃผ๋ฌธ ์™„๋ฃŒ, ์˜ˆ๋งค ์ƒ์„ฑ, ๊ฒฐ์ œ ์™„๋ฃŒ, ์‹œ๋„ ์„ฑ๊ณต, Outbox ํ–‰ ์ €์žฅ์„ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ปค๋ฐ‹ํ•œ๋‹ค.
  • ๊ทœ์น™
    • ํ™•์ • ๋‹จ๊ณ„์—์„œ ์‹œ๋„๊ฐ€ ์ด๋ฏธ FAILED๋ฉด ๊ฑฐ์ ˆํ•œ๋‹ค. Toss๋Š” ์Šน์ธํ–ˆ๋Š”๋ฐ ๊ธฐ๋ก๋งŒ ์‹คํŒจ์ธ ๊ฒฝ์šฐ์ด๋ฉฐ, ์ง€๊ธˆ์€ ๊ฐ์ง€๋งŒ ํ•˜๊ณ  ๋˜์‚ด๋ฆด ๊ฒฝ๋กœ๊ฐ€ ์—†๋‹ค
    • ์ถœ๋ฐœ์ด ์ง€๋‚ฌ๊ฑฐ๋‚˜ ์ขŒ์„์„ ๋นผ์•—๊ฒผ์œผ๋ฉด ํ™•์ •ํ•˜์ง€ ์•Š๊ณ  ์ˆ˜๋™ ํ™•์ธ์œผ๋กœ ๋‚จ๊ธด๋‹ค. ํ™•์ •์€ ์‚ฌ์œ ๋งŒ ์‹ค์–ด ์ค‘๋‹จํ•˜๊ณ , ์‹œ๋„ ๋งˆํ‚น๊ณผ ์ขŒ์„ ํ•ด์ œ๋Š” Payment ์ž ๊ธˆ์ด ํ’€๋ฆฐ ๋’ค PaymentConfirmService๊ฐ€ ํ•œ๋‹ค
    • seat_booking์— ์ขŒ์„, ๊ตฌ๊ฐ„ ์œ ๋‹ˆํฌ ์ œ์•ฝ์ด ์—†๊ณ  ์˜ˆ๋งค ์ƒ์„ฑ๋„ ์ขŒ์„ ์ถฉ๋Œ์„ ๋ณด์ง€ ์•Š๋Š”๋‹ค. ๊ฒน์นจ์€ ๊ฒฐ์ œ ์ค€๋น„์™€ ํ™•์ • ๋‹จ๊ณ„์˜ DB ์žฌ๊ฒ€์ฆ์œผ๋กœ ๋ง‰์œผ๋ฉฐ, ์ œ์•ฝ ์ž์ฒด๋Š” #280์ด๋‹ค

์‹คํŒจ ์‘๋‹ต

๊ฒฝ์šฐ ์‘๋‹ต ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•  ์ผ
Toss ๊ฑฐ์ ˆ (4xx) Toss ์ƒํƒœ ์ฝ”๋“œ ๊ทธ๋Œ€๋กœ ์‹คํŒจ ์•ˆ๋‚ด
๋ฏธ์ „์†ก 503 PAYMENT_118 ๋ฐ”๋กœ ๋‹ค์‹œ ์‹œ๋„ํ•ด๋„ ๋œ๋‹ค
๊ฒฐ๊ณผ ๋ถˆ๋ช…, ์•„์ง ์ฒ˜๋ฆฌ ์ค‘ 409 PAYMENT_113 ์ž ์‹œ ๋’ค ๊ฐ™์€ ์š”์ฒญ์œผ๋กœ ๋‹ค์‹œ ํ™•์ธํ•œ๋‹ค. ์ž๋™ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š๋Š”๋‹ค
์ด๋ฏธ ์‹คํŒจํ•œ ์‹œ๋„ 409 PAYMENT_112 ์ƒˆ๋กœ ๊ฒฐ์ œํ•œ๋‹ค
์ˆ˜๋™ ํ™•์ธ ๋Œ€์ƒ 409 PAYMENT_117 ๊ณ ๊ฐ์„ผํ„ฐ
ํ™•์ • ๋‹จ๊ณ„์—์„œ ์‹œ๋„์— ์ €์žฅ๋œ ๊ฒฐ์ œ ํ‚ค๊ฐ€ ์—†์Œ 500 PAYMENT_119 ๋‹ค์‹œ ์‹œ๋„ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์„œ๋ฒ„ ์˜ค๋ฅ˜์ด๋ฉฐ ์šด์˜ ํ™•์ธ์ด ํ•„์š”ํ•˜๋‹ค

์„ค๊ณ„ ๊ฒฐ์ •

์Šน์ธ์€ ์‹œ์ž‘, Toss ํ˜ธ์ถœ, ํ™•์ • ์„ธ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆˆ๋‹ค

  • ๋งฅ๋ฝ: Toss ํ˜ธ์ถœ ์ค‘์— ์„œ๋ฒ„๊ฐ€ ์ฃฝ๊ฑฐ๋‚˜ ์‘๋‹ต์„ ๋ชป ๋ฐ›์œผ๋ฉด, ๋ˆ์€ ๋‚˜๊ฐ”๋Š”๋ฐ ์•„๋ฌด ๊ธฐ๋ก๋„ ์—†์„ ์ˆ˜ ์žˆ๋‹ค. Toss ํ˜ธ์ถœ์„ DB ํŠธ๋žœ์žญ์…˜ ์•ˆ์— ๋‘๋ฉด ๊ทธ ๊ธฐ๋ก๋„ ํ•จ๊ป˜ ๋กค๋ฐฑ๋œ๋‹ค.
  • ๊ฒฐ์ •: Toss๋ฅผ ๋ถ€๋ฅด๊ธฐ ์ „์— ์ง„ํ–‰ ์ค‘ ์‹œ๋„๋ฅผ ๋ณ„๋„ ํŠธ๋žœ์žญ์…˜(TX A, REQUIRES_NEW)์œผ๋กœ ๋จผ์ € ์ปค๋ฐ‹ํ•œ๋‹ค. Toss ํ˜ธ์ถœ์€ ํŠธ๋žœ์žญ์…˜ ๋ฐ–์—์„œ ํ•˜๊ณ , ์„ฑ๊ณตํ•˜๋ฉด ํ™•์ •์„ ๋˜ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜(TX B)์œผ๋กœ ์ปค๋ฐ‹ํ•œ๋‹ค.
  • ๊ฒฐ๊ณผ: ์–ด๋–ค ์‹œ์ ์— ์žฅ์• ๊ฐ€ ๋‚˜๋„ ์ง„ํ–‰ ์ค‘ ์‹œ๋„๊ฐ€ ๋‚จ์•„, ๋‹ค์‹œ ์š”์ฒญํ•˜๋ฉด Toss ์กฐํšŒ๋กœ ๋งž์ถœ ์ˆ˜ ์žˆ๋‹ค. ํ™•์ •์€ ์ฃผ๋ฌธ, ์˜ˆ๋งค, ๊ฒฐ์ œ, ์‹œ๋„, Outbox๋ฅผ ํ•œ ๋ฒˆ์— ์ปค๋ฐ‹ํ•˜๋ฏ€๋กœ ์ผ๋ถ€๋งŒ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค.

์‹œ๋„ ID๋ฅผ paymentKey์—์„œ ๊ณ„์‚ฐํ•˜๊ณ  ์œ ๋‹ˆํฌ ์ œ์•ฝ์œผ๋กœ ๋ฉฑ๋“ฑ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค

  • ๋งฅ๋ฝ: ๊ฐ™์€ ๊ฒฐ์ œ์˜ ์Šน์ธ ์š”์ฒญ์ด ๋™์‹œ์— ๋˜๋Š” ๋ฐ˜๋ณตํ•ด์„œ ์˜จ๋‹ค. DB PK๋Š” ์ €์žฅํ•ด์•ผ ์ •ํ•ด์ง€๋ฏ€๋กœ, ๋‹ค์‹œ ์˜จ ์š”์ฒญ์ด ์ด์ „ ์‹œ๋„๋ฅผ ์ฐพ๋Š” ํ‚ค๋กœ ์“ธ ์ˆ˜ ์—†๋‹ค.
  • ๊ฒฐ์ •: attemptId = sha256("apv:" + paymentKey)๋กœ ๊ฐ™์€ ์š”์ฒญ์ด ํ•ญ์ƒ ๊ฐ™์€ ํ‚ค๋ฅผ ๊ฐ–๊ฒŒ ํ•˜๊ณ , attempt_id์— ์œ ๋‹ˆํฌ ์ œ์•ฝ์„ ๊ฑด๋‹ค.
  • ๊ฒฐ๊ณผ: ๋™์‹œ์— ์˜จ ๋‘ ์š”์ฒญ ์ค‘ ํ•˜๋‚˜๋งŒ ์‹œ๋„๋ฅผ ๋งŒ๋“ ๋‹ค. ์ง„ ์ชฝ์€ ์œ ๋‹ˆํฌ ์ถฉ๋Œ์„ ๋ฐ›์•„ ๊ธฐ์กด ์‹œ๋„์˜ ์žฌ์š”์ฒญ ํ๋ฆ„์œผ๋กœ ๊ฐ„๋‹ค. ์ทจ์†Œ๋Š” ํ•œ ๊ฒฐ์ œ์— ์—ฌ๋Ÿฌ ๋ฒˆ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์–ด cnl:{paymentKey}:{์ˆœ๋ฒˆ}์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๋„๋ก ์ค€๋น„๋ผ ์žˆ๋‹ค.

๊ฐ™์€ ๊ฒ€์ฆ์„ ์„ธ ๋ฒˆ ํ•œ๋‹ค

  • ๋งฅ๋ฝ: ์ž ๊ธˆ ์—†๋Š” ์‚ฌ์ „ ๊ฒ€์ฆ๊ณผ ์‹ค์ œ ์ปค๋ฐ‹ ์‚ฌ์ด์— ๋‹ค๋ฅธ ์š”์ฒญ์ด ๋ผ์–ด๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฒฐ์ •: ์‹œ์ž‘(์ž ๊ธˆ ์—†์Œ)์—์„œ ๋นจ๋ฆฌ ๊ฑธ๋Ÿฌ Toss ํ˜ธ์ถœ์„ ์•„๋ผ๊ณ , TX A์™€ TX B์—์„œ ๊ฒฐ์ œ๋ฅผ SELECT FOR UPDATE๋กœ ์ž ๊ทผ ๋’ค ๋‹ค์‹œ ๊ฒ€์ฆํ•œ๋‹ค. ๋งˆ์ง€๋ง‰ ๋ฐฉ์–ด๋Š” attempt_id ์œ ๋‹ˆํฌ ์ œ์•ฝ์ด๋‹ค.
  • ๊ฒฐ๊ณผ: ๋™์‹œ ์š”์ฒญ์ด ์™€๋„ ์Šน์ธ๊ณผ ํ™•์ •์€ ํ•œ ๋ฒˆ์”ฉ๋งŒ ์ผ์–ด๋‚œ๋‹ค. ์‹œ๋„ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š” ๋ชจ๋“  ๊ฒฝ๋กœ๊ฐ€ ๊ฒฐ์ œ๋ฅผ ๋จผ์ € ์ž ๊ทธ๊ณ  ์‹œ๋„๋ฅผ ์ฝ๋Š”๋‹ค. ์ž ๊ทธ๊ธฐ ์ „์— ์ฝ์œผ๋ฉด ๋จผ์ € ์ปค๋ฐ‹๋œ ์„ฑ๊ณต์„ ์‹คํŒจ๋กœ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๊ณผ ๋ถˆ๋ช…์€ ์‹คํŒจ๊ฐ€ ์•„๋‹ˆ๋ผ ์ง„ํ–‰ ์ค‘์œผ๋กœ ๋‚จ๊ธฐ๊ณ  409๋กœ ์‘๋‹ตํ•œ๋‹ค

  • ๋งฅ๋ฝ: Toss 5xx๋‚˜ ํƒ€์ž„์•„์›ƒ์€ Toss๊ฐ€ ์Šน์ธํ•œ ๋’ค ์‘๋‹ต๋งŒ ์‹คํŒจํ–ˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ 5xx๋ฅผ ๊ทธ๋Œ€๋กœ ๋‚ด๋ฆฌ๋ฉด, ์žฌ์‹œ๋„ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์Šน์ธ์„ ๋‹ค์‹œ ๋ณด๋‚ด ์ด์ค‘ ์ฒญ๊ตฌ๊ฐ€ ๋œ๋‹ค.
  • ๊ฒฐ์ •: ๊ฒฐ๊ณผ ๋ถˆ๋ช…์€ ์‹œ๋„๋ฅผ ์ง„ํ–‰ ์ค‘์œผ๋กœ ๋‘๊ณ  ์žฌ์‹œ๋„๋ฅผ ๋ถ€๋ฅด์ง€ ์•Š๋Š” 409๋กœ ์‘๋‹ตํ•œ๋‹ค. ๊ฐ™์€ ์š”์ฒญ์ด ๋‹ค์‹œ ์˜ค๋ฉด ์Šน์ธ์„ ๋‹ค์‹œ ๋ณด๋‚ด์ง€ ์•Š๊ณ  Toss์— ์กฐํšŒํ•œ๋‹ค. Toss ํ˜ธ์ถœ๋„ ์กฐํšŒ(GET)๋งŒ ์ž๋™ ์žฌ์‹œ๋„ํ•˜๊ณ  ์Šน์ธ(POST)์€ ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š๋Š”๋‹ค. Toss๋Š” POST์— Idempotency-Key๋ฅผ ์ง€์›ํ•˜์ง€๋งŒ(Toss ๋ฌธ์„œ ๊ธฐ์ค€ 15์ผ dedup, 2026-10 ํ™•์ธ) ์Šน์ธ์€ ์•„์ง ํ—ค๋”๋ฅผ ๋ณด๋‚ด์ง€ ์•Š๊ณ (#260) ์ทจ์†Œ๋Š” ํ˜ธ์ถœ๋งˆ๋‹ค ์ƒˆ ํ‚ค๋ฅผ ๋งŒ๋“ค์–ด, ์ „์†ก ์ธต์—์„œ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ ๋ณ„๊ฐœ ์š”์ฒญ์œผ๋กœ ๋ฐ›๋Š”๋‹ค. ๋ฏธ๋„๋‹ฌ, ๊ฒฐ๊ณผ ๋ถˆ๋ช…, ๊ฑฐ์ ˆ์˜ ํŒ์ •์€ TossPaymentClient๊ฐ€ ์‹ค์–ด ๋ณด๋‚ธ ์ „์†ก ๋‹จ๊ณ„๋กœ PaymentGatewayException์ด ํ•˜๊ณ , ์‹œ๋„ ๊ธฐ๋ก๊ณผ HTTP ์‘๋‹ต์ด ๊ฐ™์€ ํŒ์ •์„ ์“ด๋‹ค.
  • ๊ฒฐ๊ณผ: ์ด์ค‘ ์ฒญ๊ตฌ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  ์Šน๊ฐ์ด ๋‹ค์‹œ ์š”์ฒญํ•˜์ง€ ์•Š์œผ๋ฉด ์ง„ํ–‰ ์ค‘ ์‹œ๋„๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค. ์ด๋ฅผ ๋Œ€์‚ฌํ•˜๋Š” ๋ณต๊ตฌ Worker๊ฐ€ ์˜ค๋ž˜๋œ ์‹œ๋„๋ฅผ ์ •๊ธฐ์ ์œผ๋กœ ๊ฐ€์ ธ๊ฐ€ ์ฒ˜๋ฆฌํ•œ๋‹ค.

๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ฅด๋Š” ๋™์•ˆ๋งŒ ์ขŒ์„์„ ๋ถ™์žก๋Š”๋‹ค

  • ๋งฅ๋ฝ: ์˜ˆ์•ฝ TTL์€ 10๋ถ„์ธ๋ฐ ๊ฒฐ๊ณผ ๋ถˆ๋ช…์ธ ์‹œ๋„๋Š” ๊ทธ๋ณด๋‹ค ์˜ค๋ž˜ ๋‚จ๋Š”๋‹ค. ๊ทธ ์‚ฌ์ด ์ขŒ์„์ด ํ’€๋ ค ๋‚จ์ด ๊ฐ€์ ธ๊ฐ€๋ฉด, Toss๊ฐ€ ์Šน์ธํ•œ ๊ฒฐ์ œ๋ฅผ ํ™•์ •ํ•  ์ˆ˜ ์—†๋‹ค. ๋ฐ˜๋Œ€๋กœ ๊ฒฐ์ œ ๋‚ด๋‚ด ์ขŒ์„์„ ์˜๊ตฌ ์ ์œ ํ•˜๋ฉด ์ดํƒˆํ•œ ๊ฒฐ์ œ๊ฐ€ ์ขŒ์„์„ ์šดํ–‰์ผ๊นŒ์ง€ ๋ฌถ๋Š”๋‹ค.
  • ๊ฒฐ์ •: ๊ฒฐ๊ณผ ๋ถˆ๋ช…(Toss 5xx, ํƒ€์ž„์•„์›ƒ, ์กฐํšŒ ์‹คํŒจ, ์กฐํšŒ๊ฐ€ ์•„์ง ์ฒ˜๋ฆฌ ์ค‘)์ผ ๋•Œ๋งŒ reservation_payment_hold.lua๋กœ ์ขŒ์„ field์˜ ๋งŒ๋ฃŒ๋ฅผ ์—†์• ๊ณ , ํ™•์ • ์‹คํŒจ์™€ ์ˆ˜๋™ ํ™•์ธ์œผ๋กœ ๋๋‚˜๋ฉด reservation_payment_release.lua๋กœ ๋˜๋Œ๋ฆฐ๋‹ค. ํ˜ธ์ถœ ์ง€์ ์€ PaymentSeatGuard๊ฐ€ ๋ชจ์œผ๋ฉฐ ๋ณดํ˜ธ ์‹คํŒจ๋Š” ๋กœ๊ทธ๋งŒ ๋‚จ๊ธด๋‹ค.
  • ๊ฒฐ๊ณผ: ์ •์ƒ ์Šน์ธ ๊ฒฝ๋กœ๋Š” Redis ํ˜ธ์ถœ์ด ๋Š˜์ง€ ์•Š๊ณ , ๋…ธ์ถœ์ด ์‚ฌ๋žŒ์ด ๋ด์•ผ ํ•˜๋Š” ์‹œ๋„๋กœ ํ•œ์ •๋œ๋‹ค. ๋Œ€์‹  ๋ณดํ˜ธ๋ฅผ ๊ฑธ๊ณ  ํ•ด์ œ๊ฐ€ ์˜ค์ง€ ์•Š์œผ๋ฉด(์Šน๊ฐ ์ดํƒˆ, ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ) ์ขŒ์„์ด ๊ฐ์ฐจ ํ‚ค ๋งŒ๋ฃŒ๊นŒ์ง€ ๋‚จ๋Š”๋‹ค. ๊ณ ์•„ R: field ์ •๋ฆฌ๋Š” #274๋‹ค.

ํšŒ๋ณต ํŒ์ •์„ ๋ณ„๋„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค

  • ๋งฅ๋ฝ: ์ง„ํ–‰ ์ค‘์ธ ์‹œ๋„๋ฅผ Toss์— ์กฐํšŒํ•ด ๋งž์ถ”๋Š” ํŒ๋‹จ์€ ์Šน๊ฐ์˜ ์žฌ์š”์ฒญ๊ณผ ๋ณต๊ตฌ Worker๊ฐ€ ํ•จ๊ป˜ ์“ด๋‹ค. ์ด ํŒ๋‹จ์ด ์Šน์ธ ์‹œ์ž‘ ๋‹จ๊ณ„์— ๋“ค์–ด ์žˆ์œผ๋ฉด ๋ณต๊ตฌ Worker๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์‹œ์ž‘ ๋‹จ๊ณ„๋Š” ์š”์ฒญ๊ณผ ํšŒ์› ๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์™ธ๋กœ ๋Œ๋ ค์ฃผ๋Š” ๊ตฌ์กฐ๋‹ค.
  • ๊ฒฐ์ •: ์กฐํšŒ์™€ ํŒ์ •์„ PaymentApprovalReconciler๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ReconcileDecision ์—ฌ์„ฏ ๊ฐ€์ง€ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋Œ๋ ค์ค€๋‹ค. ์Šน๊ฐ ๊ฒฝ๋กœ๋Š” ํŒ์ •์„ ์‹œ๋„ ์ƒํƒœ ๊ธฐ๋ก๊ณผ HTTP ์‘๋‹ต์œผ๋กœ ๋ฐ”๊พธ๊ณ , ๋ณต๊ตฌ Worker๋Š” ์ƒํƒœ ๊ธฐ๋ก์œผ๋กœ๋งŒ ๋ฐ”๊พผ๋‹ค.
  • ๊ฒฐ๊ณผ: ๋‘ ๊ฒฝ๋กœ๊ฐ€ ํ•˜๋‚˜์˜ ํŒ์ •์„ ๊ณต์œ ํ•œ๋‹ค. ํŒ์ •๋ณ„ ๊ฑด์ˆ˜๋Š” payment.recovery.decision ์ง€ํ‘œ๋กœ ๋ชจ์ธ๋‹ค. ReconcileDecision์€ sealed์ด๋ฏ€๋กœ ํŒ์ •์ด ๋Š˜๋ฉด ๋ชจ๋“  ์†Œ๋น„์ž์—์„œ ์ปดํŒŒ์ผ์ด ๋ฉˆ์ถ”๊ณ , ์ƒˆ ํŒ์ •์ด ๊ธฐ์กด ์‘๋‹ต์œผ๋กœ ์กฐ์šฉํžˆ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ตœ๋Œ€ ๋Œ€๊ธฐ ์ดˆ๊ณผ๋ฅผ ๊ฐ•์ œ ์‹คํŒจ๋กœ ๊ธฐ๋กํ•˜์ง€ ์•Š๋Š”๋‹ค

  • ๋งฅ๋ฝ: ๋ณต๊ตฌ Worker๊ฐ€ ์•„๋ฌด๋ฆฌ ์žฌ์‹œ๋„ํ•ด๋„ Toss ์‘๋‹ต์„ ๋ชป ๋ฐ›๋Š” ์‹œ๋„๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋์—†์ด ์žฌ์‹œ๋„๋ฅผ ๊ฑธ๋ฉด ๊ทธ ์‹œ๋„๋Š” ์˜์›ํžˆ IN_PROGRESS๋กœ ๋‚จ์•„ ์ขŒ์„๊ณผ ์ž์›์„ ๋ถ™์žก๋Š”๋‹ค.
  • ๊ฒฐ์ •: RecoveryBackoffPolicy์˜ ์ตœ๋Œ€ ๋Œ€๊ธฐ๋ฅผ ๋„˜๊ธฐ๋ฉด ์ž๋™์œผ๋กœ FAILED๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š๊ณ  REVIEW_RECOVERY_TIMEOUT ์‚ฌ์œ ๋กœ REVIEW_REQUIRED์— ์˜ฌ๋ ค ์‚ฌ๋žŒ์ด Toss ์ชฝ์„ ์ง์ ‘ ํ™•์ธํ•˜๊ฒŒ ํ•œ๋‹ค.
  • ๊ฒฐ๊ณผ: ์Šน์ธ๋์„ ์ˆ˜๋„ ์žˆ๋Š” ์‹œ๋„๋ฅผ ์ž๋™์œผ๋กœ ์‹คํŒจ ์ฒ˜๋ฆฌํ•ด ์ด์ค‘ ์ฒญ๊ตฌ๋‚˜ ํ™˜๋ถˆ ๋ˆ„๋ฝ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  ์ˆ˜๋™ ํ™•์ธ ๋Œ€๊ธฐ๊ฐ€ ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ์–ด payment.attempt.review_required_rows ๊ฒŒ์ด์ง€๋กœ ์ง€์ผœ๋ณธ๋‹ค. REVIEW_REQUIRED์—๋Š” ์ฒ˜๋ฆฌ๋๋‹ค๋Š” ํ‘œ์‹์ด ์—†์–ด ์ด ๊ฒŒ์ด์ง€๋Š” ์ค„์ง€ ์•Š์œผ๋ฏ€๋กœ, ์•Œ๋ฆผ์€ ์ตœ๊ทผ 24์‹œ๊ฐ„ ์•ˆ์— ๋ฐ”๋€ ํ–‰๋งŒ ์„ธ๋Š” payment.attempt.review_required_recent_rows์— ๊ฑธ๊ณ  ์ „์ฒด ํ–‰ ๊ฒŒ์ด์ง€๋Š” ์ „์ฒด ์ ์ฒด ๊ทœ๋ชจ๋ฅผ ๋ณด๋ ค๊ณ  ๋‘”๋‹ค. ํ•ด์†Œ ํ‘œ์‹์€ #302 ๋ฒ”์œ„๋‹ค.

๋ฏธ์ „์†ก์€ ์‹คํŒจ์™€ ๊ตฌ๋ถ„ํ•œ๋‹ค

  • ๋งฅ๋ฝ: attemptId๊ฐ€ paymentKey์—์„œ ๊ฒฐ์ •๋˜๋ฏ€๋กœ, ์‹คํŒจ๋กœ ๊ธฐ๋กํ•˜๋ฉด ๊ทธ paymentKey๋กœ๋Š” ๋‹ค์‹œ ์Šน์ธํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์š”์ฒญ์ด Toss์— ๊ฐ€์ง€๋„ ์•Š์•˜๋‹ค๋ฉด ๋‹ค์‹œ ๋ณด๋‚ด๋„ ์œ„ํ—˜์ด ์—†๋‹ค.
  • ๊ฒฐ์ •: ๋ฏธ๋„๋‹ฌ์ด ํ™•์ •์ธ ์‹คํŒจ๋Š” NOT_SENT๋กœ ๊ธฐ๋กํ•˜๊ณ  503์œผ๋กœ ์‘๋‹ตํ•œ๋‹ค. ๋‹ค์‹œ ์˜ค๋ฉด ๊ฐ™์€ ์‹œ๋„๋ฅผ ์ง„ํ–‰ ์ค‘์œผ๋กœ ๋˜๋Œ๋ ค ์Šน์ธ์„ ๋‹ค์‹œ ๋ณด๋‚ธ๋‹ค.
  • ๊ฒฐ๊ณผ: ์ผ์‹œ์ ์ธ ์—ฐ๊ฒฐ ์‹คํŒจ๋กœ ๊ฒฐ์ œ์ฐฝ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์—ด ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋‹ค์‹œ ๋ณด๋‚ผ ๋•Œ๋„ ์˜ˆ์•ฝ ์ƒ์กด๊ณผ ๊ฒฐ์ œ ์ƒํƒœ๋ฅผ ์ƒˆ ์Šน์ธ์ฒ˜๋Ÿผ ๋‹ค์‹œ ํ™•์ธํ•œ๋‹ค.