Backend Development 5 min read

Preventing Order Loss and Duplicate Submissions in Payment Systems

This article outlines a simplified order flow involving payment gateways and third‑party channels, identifies external and internal order‑loss scenarios, and proposes practical measures such as intermediate “payment‑in‑progress” states, timeout queries, idempotent handling, retry mechanisms, and Redis‑based duplicate‑submission prevention to ensure reliable order processing.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Preventing Order Loss and Duplicate Submissions in Payment Systems

As shown in the figure, the simplified order process starts with submitting an order and then making a payment. Payment typically goes through a payment gateway (payment center), which interacts with third‑party payment channels such as WeChat, Alipay, and UnionPay. After a successful payment, an asynchronous notification updates the payment center, which then notifies the business application; each business updates its own order status.

During this process, order loss may occur. Whether due to a timeout without receiving a callback notification or a program error, various reasons can cause the server to fail to update the order status even though the user has paid successfully, leading to complaints or duplicate payments.

Order loss caused by steps ③ and ⑤ is called external order loss; loss caused by steps ④ and ⑥ is called internal order loss.

To prevent order loss, the following measures can be applied:

1. Add an intermediate state "payment in progress" to the payment order. When the same order attempts payment, first check whether a payment record with the "payment in progress" state exists, and lock the pre‑pay operation. After payment completes, update the record to "payment successful".

2. The payment center should define a timeout (e.g., 30 seconds). If no success callback is received within this window, actively query the payment result at intervals (e.g., every 10 s, 20 s, 30 s). If the result is still unavailable after the maximum number of queries, handle it as an exception.

3. Once the payment center receives the payment result, it should synchronize the result to the business system, either via MQ or direct calls. Direct calls should include retry logic (e.g., using SpringBoot Retry).

4. Both the payment center and the business applications must ensure idempotent handling of the payment result notification, processing each message only once and ignoring duplicates.

5. Business applications should also perform proactive timeout queries for payment results.

For proactive timeout queries, place the payment orders that need querying into a dedicated table and use a scheduled task to scan and process them.

To prevent duplicate order submissions, the following approach can be used:

When creating an order, compute a hash value from the order information and check Redis for an existing key. If the key exists, reject the duplicate submission; otherwise, generate a new key with an expiration time, store it in Redis, and proceed with order creation. This effectively blocks identical operations within a short time window.

Below is an illustration of WeChat Pay best practices:

Source: cnblogs.com/cjsblog/p/14516909.html

BackendRedisorder processingretryIdempotencypayment
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.