How to Prevent Duplicate Payments in E‑commerce Orders
This article explains the complete e‑commerce payment workflow, identifies the causes of duplicate payments such as missing deduplication, order loss and multi‑channel issues, and presents practical backend solutions including distributed locking, result caching, payment‑flow cancellation, active polling, and sync‑async notification strategies to ensure order consistency and improve payment success rates.
Overview of Order Payment Process
We first look at the simplified e‑commerce order payment flow.
From order creation to payment completion:
Order/Checkout : The order is created in an unpaid state; all payment‑related amounts are derived from the checkout information.
Apply Payment : The user initiates a payment request; the payment service creates a payment record with status UNPAID .
Initiate Payment : The payment service calls a third‑party provider. For wallet‑type payments, a payment link or QR code is returned to the client.
Wallet Payment : The user completes the payment through the wallet. The handling differs across platforms: APP端 : Most domestic shopping occurs on apps. The app launches the wallet and completes payment. WAP端 : Mobile web pages directly launch the wallet; if launching fails, a fallback page is shown. PC端 : The PC opens a checkout page that displays a QR code for the user to scan with a wallet.
Payment Callback : After the user finishes payment, the third‑party platform calls back the merchant with the result.
Synchronize Order Status : Once the payment service confirms success, it updates the order status from UNPAID to READY_FOR_SHIPMENT . The client can obtain the new status via polling, long‑polling, or server‑push.
Payment‑record status changes:
Why Duplicate Payments Occur
Missing deduplication: On PC, each click generates a new QR code and payment record; scanning multiple codes leads to duplicate payments.
Order loss ("掉单"): External loss – third‑party payment status is not synchronized to the shop. Internal loss – payment service status is not synchronized to the order service or the client does not fetch the latest status.
Multi‑channel payment: Users may try different payment methods (e.g., Boleto then PayPal) and end up paying twice when the first payment is still pending.
How to Prevent Duplicate Payments
Locking
Both the Apply Payment and Payment Callback steps should acquire a lock at the order level to avoid concurrent duplicate operations. Distributed locks (e.g., Redis) are commonly used.
Caching Results
Both successful payment applications and callbacks should cache the result. Subsequent payment attempts must first check the cached status.
Cancel In‑Progress Payment Records
If a user repeats a payment while a previous PAYING record exists, the system should cancel the old record before creating a new one, unless the old record's final status is unknown.
Refund Already Paid Records
If a third‑party does not support cancellation and the user initiates another payment, the system can allow multiple payments but must refund the later ones once a successful record is detected.
Active Polling & Retry to Prevent Order Loss
Polling After Payment Initiation
If a callback is missed, the client should start polling the payment status a few seconds after the request, continuing until a final state is obtained.
Scheduled Task Polling : Scan the payment table periodically and query the third‑party for each PAYING record. Drawbacks: database load spikes and coarse‑grained intervals.
Delayed‑Message Polling : After a payment request, send a delayed message; when consumed, query the status and, if still pending, send another delayed message. This reduces DB pressure but adds implementation complexity.
Sync + Async Notification to Prevent Internal Loss
When the payment service receives an async callback or a polling result, it must notify the order service. Use a synchronous HTTP call (with retries) combined with an asynchronous message (e.g., MQ) to guarantee eventual consistency.
Synchronous call – may fail due to network issues; retry logic is needed.
Asynchronous notification – leverages message‑queue retry mechanisms for higher reliability.
Client‑Side State Synchronization
Clients can obtain the latest order status via:
Pull : Periodic polling after the user returns to the order page.
Push : Server‑side push using WebSocket for web or third‑party push services for mobile apps.
Avoid External Jumps in Client Payment
From a product and technical perspective, the payment step should stay within the app or page whenever possible. PC should display a QR code instead of redirecting; mobile web and apps should embed the payment page if the provider allows it (e.g., Alipay’s in‑app payment).
In summary, preventing duplicate payments requires a combination of order‑level locking, result caching, careful handling of in‑progress records, proactive polling, reliable sync/async notifications, and minimizing external redirects.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.