पाठ 20 / 25
Idempotency Keys for Safe Retries
Implement server-side idempotency keys so clients can retry non-idempotent operations.
Making POST safe to repeat
Retries are only safe for idempotent operations. Creating a payment or an order with POST is not idempotent: if the response is lost, the client cannot tell whether the order was created, and retrying might create a duplicate. The fix is an idempotency key: the client generates a unique key per logical operation (a UUID) and sends it in a header such as Idempotency-Key. The server stores the key with the request fingerprint and the result. If the same key arrives again, the server returns the stored result instead of performing the operation again; if the key arrives with a different request body, it returns an error; if the first request is still in progress, it returns a conflict or waits. Keys are kept for a defined retention period (often 24 hours or more). Payment APIs such as Stripe popularised this pattern, and an IETF draft describes the Idempotency-Key header for HTTP APIs.
Server-side idempotency key handling
The key record and the business write are tied together so retries return the original result.
import hashlib, json
def create_order(request, db):
key = request.headers.get("Idempotency-Key")
if not key:
return 400, {"error": "Idempotency-Key header required"}
fingerprint = hashlib.sha256(json.dumps(request.json, sort_keys=True).encode()).hexdigest()
with db.transaction() as tx:
row = tx.fetch_one("SELECT fingerprint, status_code, body FROM idempotency_keys WHERE key = %s FOR UPDATE", (key,))
if row:
if row.fingerprint != fingerprint:
return 422, {"error": "key reused with a different request"}
return row.status_code, json.loads(row.body) # replay stored result
order = tx.insert_order(request.json)
body = {"orderId": order.id, "status": "PLACED"}
tx.execute("INSERT INTO idempotency_keys (key, fingerprint, status_code, body, created_at) "
"VALUES (%s, %s, 201, %s, now())", (key, fingerprint, json.dumps(body)))
return 201, bodyA receipt number at a counter
If you are unsure whether the clerk processed your form, you show your token number. The clerk looks it up and hands you the same receipt instead of processing the form twice.
त्वरित जाँच: A client retries POST /payments with the same Idempotency-Key after a timeout. What should the server do if the first attempt succeeded?
- Charge the customer again
- Return 404
- Ignore the key and process normally
- Return the stored result of the first attempt without charging again
Answer
Return the stored result of the first attempt without charging again — The stored response is replayed, making the retry safe.