← Back to the blog

Integration reliability

Idempotency in plain English: stop retries from creating duplicates

Use stable operation keys, uniqueness constraints, and recorded outcomes so a retried request does not repeat a business action.

2 minute read

The ambiguous outcome problem

A client sends “create this order.” The server creates it, but the response is lost. The client cannot tell whether nothing happened or everything happened, so it retries. Without a duplicate control, the customer now has two orders.

Avoiding all retries is not the answer. Temporary failures are normal. The design needs a way to recognize that two requests represent the same intended business action.

Give the operation a stable identity

Create or preserve an idempotency key before the first attempt. The key should identify the operation, not merely the transport request. Store it with the operation status and result.

When the same key arrives again, return the recorded result or safely continue the unfinished operation. Do not generate a fresh key on every retry; that defeats the mechanism.

  • Use a provider event ID when it is stable and unique.
  • For client-created actions, generate the key before sending.
  • Protect the key with a database uniqueness constraint.
  • Reject reuse of one key with meaningfully different input.

A lookup is not enough

Two workers can both check for a record, find nothing, and create duplicates at the same time. The database must enforce the invariant with a unique key or an atomic operation.

The same caution applies when one business action touches several systems. Record the local operation first, then track each downstream step so a retry resumes rather than repeats completed work.

Test the uncomfortable cases

Send the same request twice at once. Drop the response after the write. Fail between two downstream calls. Restart a worker mid-operation. Then verify that the final business state is still correct and that an operator can see what happened.

Idempotency is complete when duplicates are prevented under concurrency and partial failure, not only when the same request is sent twice in a calm test.

Bounded Works

Better follow-up and less busywork for small businesses. Have a task like this? Tell me what happens today and what you’d like to change.

Book a 20-minute call