Three‑layer mechanism to ensure a single charge for repeated payment attempts

The article explains a three‑layer strategy—pre‑intercept via Redis locks or temporary tokens, mid‑process control using order status and optimistic locking, and post‑fallback with delayed MQ messages and nightly reconciliation—to guarantee that multiple user clicks result in only one successful payment.

Lobster Programming
Lobster Programming
Lobster Programming
Three‑layer mechanism to ensure a single charge for repeated payment attempts

When a user clicks the payment button multiple times because of network latency or UI lag, the system must ensure that only one request actually charges the order while the others are filtered out.

1. Pre‑intercept mechanism

Two common implementations are used:

Distributed lock : Each payment request carries the same user‑id and order‑id. A Redis SETNX command creates a lock keyed by the order id. The first request that acquires the lock proceeds to business logic; subsequent requests fail to acquire the lock and are rejected with a “duplicate payment request” message.

Temporary token : The front‑end first obtains a token from the back‑end. The token is sent together with the payment request. The back‑end processes the request as follows:

Check whether the token is valid; if not, return an error.

Verify that the token still exists in Redis; if it has been removed, discard the request.

If the token is present, delete it from Redis and then execute the business logic. If the business fails, the back‑end returns a special flag so the front‑end knows to request a new token before retrying.

2. Mid‑process control mechanism

After passing the pre‑intercept, the request calls a third‑party payment provider. If the network stalls and the Redis lock expires, the user may click again. To prevent duplicate charges, the system falls back to a database‑level guard that combines an order status machine with an optimistic lock.

The order table contains a status field (e.g., 0 = "pending", 1 = "paying"). The transition is performed with an UPDATE statement that only succeeds when the current status is 0:

update order set status = 1 where orderId = "order_1234" and status = 0

Because the UPDATE acquires a row‑level exclusive lock, only one concurrent request can change the status from 0 to 1; the others receive an update count of 0 and are treated as failed, thereby eliminating duplicate deductions at the database layer.

3. Post‑fallback mechanism

In extreme cases the third‑party payment succeeds but the callback is lost, causing the user to retry. Two safeguards are applied:

MQ delayed message : When a payment is initiated, a 3‑minute delayed message is sent to a message queue. After the delay, the system actively queries the third‑party for the payment result. If the payment succeeded, the local order status is updated to “paid”; if it failed, the status is set to “failed”.

Daily reconciliation : Every night a job pulls the settlement statements from the payment channels and compares them record‑by‑record with the local order table. Over‑payments are automatically refunded; under‑payments are placed into a manual error pool for human handling.

Summary

Pre‑intercept uses distributed locks or temporary tokens to block redundant requests at the earliest stage.

Mid‑process control relies on an order status machine and the database’s row‑level lock (optimistic lock) to ensure only one request can transition the order to “paying”.

Post‑fallback employs delayed MQ messages and nightly reconciliation to handle lost callbacks and guarantee eventual consistency.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MQdistributed-lockoptimistic-locktokenpayment-idempotency
Lobster Programming
Written by

Lobster Programming

Sharing insights on technical analysis and exchange, making life better through technology.

0 followers
Reader feedback

How this landed with the community

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.