Idempotency & Retry-Safe Systems · Idempotency Keys in Practice

Concurrent Duplicates and Locking

Handle two identical requests arriving at the same time.

Create a free account to save this page, take notes and track your progress. Sign in

Retries often arrive concurrently — the client timed out at 5 s while the original is still running. Claim the key atomically (INSERT … ON CONFLICT DO NOTHING, or Redis SET NX PX), and make the loser return 409 Conflict ("in progress") so the client retries later — never run the operation twice. Use a lease (locked_until) so a crashed worker's claim can be recovered.

Claiming a key

Approach Atomic claim Crash recovery
INSERT … ON CONFLICT DO NOTHING Yes (unique PK) locked_until lease + sweeper
SELECT … FOR UPDATE Yes (row lock) Lock released on crash
Redis SET NX PX Yes TTL expiry
Check-then-insert No (race) —
const lock = await redis.set(`idem:${scope}:${key}`, workerId, { NX: true, PX: 60_000 });
if (!lock) {
  const done = await db.idempotencyKey.findUnique({ where: { scope_key: { scope, key } } });
  if (done?.status === "completed") return res.status(done.responseStatus).json(done.responseBody);
  return res.status(409).set("Retry-After", "2").json({ title: "Request in progress" });
}

Common pitfalls

  • Check-then-insert races.
  • Holding database locks during slow external calls.
  • No lease: a crashed request blocks the key forever.

Key points

  • Atomic claim
  • Loser gets 409 + Retry-After
  • Leases for recovery

Further reading: Brandur: idempotency keys

Practice questions

Why is 'SELECT the key; if missing, INSERT it' unsafe?

Answer

Two concurrent requests can both see the key missing and both proceed, executing the operation twice; the claim must be a single atomic operation.

What does a lease (locked_until) protect against?

Answer

A worker crashing mid-request: once the lease expires, a retry can reclaim the key and finish (or resume) the operation instead of getting 409 forever.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?