Ensuring Idempotency in Order Services: Preventing Duplicate Orders and Solving the ABA Problem
This article explains how to ensure idempotency in order services by using database transactions, unique request identifiers, and version control to prevent duplicate orders and solve the ABA problem, providing practical code examples and best practices for backend developers.
1. Problem Background
The simplest solution is using a DB transaction, for example when creating an order you need to insert rows into the order table and order‑item table within the same transaction.
When the Order service calls the Pay service and a network timeout occurs, the Order service may retry, causing the Pay service to receive the same payment request twice, possibly on different nodes, so the interface must be idempotent.
2. How to Avoid Duplicate Orders
2.1 How to Determine Duplicate Requests
Check the order table before inserting to see if a duplicate order exists, but defining “duplicate” in SQL is difficult.
Even if the user places two identical orders consecutively, they may be considered duplicates.
To achieve idempotency you need to:
2.1.1 Each request must have a unique identifier
For a payment request, include the order ID; an order ID can only be paid successfully once.
2.1.2 Record that the request has been processed
In MySQL add a status field or insert a payment record before the actual payment.
2.1.3 Check if the request was processed before
If a payment record with the same order_id already exists, the unique key constraint will cause the INSERT to fail, preventing double charging.
Use the database primary‑key uniqueness constraint by providing the primary key in the INSERT statement.
Generate a globally unique order number via an “orderId generation” API and use it as the primary key of the order table; duplicate requests will carry the same order number, and the DB will allow only one INSERT to succeed.
3. Solving the ABA Problem
3.1 What is ABA
When a seller fills a tracking number 666, then corrects it to 888, the system may process the 666 update, then the 888 update, lose the success response of 666, retry, and the tracking number reverts to 666, causing data inconsistency.
3.2 Solution
Add a version column to the order table. The client reads the version together with the order data and sends it back when updating. The update statement checks the version and increments it atomically.
UPDATE orders set tracking_number = 666, version = version + 1 WHERE version = 8;If the version does not match, the update is rejected; if it matches, the update succeeds and the version is incremented, preventing ABA.
4. Summary
Create order service by pre‑generating a globally unique order ID and relying on the DB unique constraint to achieve idempotent order creation.
Update order service using a version‑checking mechanism to ensure idempotent updates and solve the ABA problem.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.