- #idempotency
- #api
- #payment-system
- #spring-boot
- #go
Tránh trừ tiền hai lần: Idempotency trong API thanh toánPrevent Double Charge: API Idempotency for Payments
Cách thiết kế API thanh toán idempotent để tránh lỗi trừ tiền hai lần, với ví dụ thực tế trong Spring Boot 3 và Go.How to design idempotent payment APIs to prevent double‑charge bugs, with practical Java Spring Boot 3 and Go examples.
Mục lụcContents· 7
Bạn có bao giờ gặp trường hợp khách hàng phàn nàn rằng họ bị trừ tiền hai lần sau khi nhấn nút "Thanh toán"? Thường thì lỗi này xuất phát từ idempotency không được thực thi đúng cách: khi một request bị retry (do timeout, network glitch, hoặc client nhấn lại) server lại thực hiện lại toàn bộ transaction.
Nguyên nhân phổ biến#
- Retry tự động của client – HTTP client (Postman, Retrofit, hoặc browser) sẽ tự gửi lại request nếu không nhận được response trong thời gian quy định.
- Timeout ở gateway – API gateway (nghĩa là Nginx, Kong, hoặc AWS API GW) có thể trả về 504 và client sẽ retry.
- Crash giữa‑chừng – Khi service bị restart ngay sau khi ghi vào DB nhưng chưa commit, transaction có thể bị thực thi lại.
Nếu không có cơ chế idempotent key, mỗi lần request được thực hiện lại, hệ thống sẽ tạo một bản ghi giao dịch mới, dẫn tới double‑charge.
Nguyên tắc idempotency#
- Idempotency‑Key: một giá trị duy nhất do client cung cấp (UUID, order‑id, hoặc hash của payload). Server phải lưu trữ key này và kết quả tương ứng.
- Idempotent operation: nếu key đã tồn tại, trả về cùng một response (status 200/201) và không thực hiện lại logic thay đổi trạng thái.
- Persist key: key phải được ghi vào DB trong cùng transaction với nghiệp vụ chính để tránh mất đồng bộ khi crash.
