← All articles
Practical guideWorkflow testing

Idempotency keys: let a retry happen without doing the job twice

A retry repeats the attempt. An idempotency key helps the service recognize the same business action. Learn what to check before calling the retry safe.

In this article
Conceptual illustration · AgentTwin journal

The response is missing. The work may already be done.

Imagine a support assistant creating a ticket. The service saves the ticket, but the assistant never receives the reply. Retrying seems reasonable. Creating another ticket is not.

An idempotency key is a stable identifier for one intended action. The service uses it to recognize a repeated request. Think of a claim number: asking about the same claim twice should not open two claims.

This guide helps you turn that idea into a test. The examples describe a test design, not a newly observed production incident.

Write saved: The service creates the ticket. Reply lost: The caller cannot see the success. Same action retried: A stable key should prevent a second ticket.
A lost reply can cause duplicate work. Illustrative test design; this diagram is not a run result.

Keep the key stable across attempts

Create the key for the business action, then reuse it on retry. A new random key for every network attempt makes the attempts look like different actions.

Situation Identity you want
First attempt to create ticket A Action A
Retry after losing its response Still action A
A separate request to create ticket B A different action

Do not assume that adding a header implements this behavior. The receiving operation must support the key, and its rules for scope, storage and expiry matter. Check your actual provider and operation.

Test the moment between saving and replying

Start with an empty synthetic ticket collection. Run the workflow without a fault. Require one ticket and one notification.

Next, introduce a timeout after the supported write commits. Keep the same starting data and required outcomes. A test that only checks the final HTTP response can miss the extra ticket. Count the saved effects too.

AgentTwin has a declared timeout-after-write fault for supported operations. The runnable sample demonstrates a ticket retry. It is a bounded synthetic API, not a simulation of every ticket vendor.

Count the notification as well

Protecting the first write does not automatically protect the next step. A retry could reuse the ticket but send the notification twice.

Write both requirements before fixing the code: one ticket for this action and one notification for that ticket. If your business permits a different notification behavior, make that explicit. A test should encode the rule you need, not a convenient count.

Also distinguish an existing unrelated record from a duplicate caused by this request. Use a known baseline and identifiers for the action being tested.

Verify the repair without lowering the bar

Change the application so the same intended action keeps the same key. Repeat the fault with the same fixtures and checks. Confirm that the requested fault actually triggered.

The useful evidence is one action despite repeated attempts. A passing run with no triggered fault does not demonstrate that behavior. A passing run after allowing two tickets does not demonstrate the repair either.

Decide whether to add this test

Start here when duplicate actions lead to manual cleanup or customer confusion. Keep your current harness if it can reproduce the lost reply and check both effects reliably.

To evaluate AgentTwin, try the sample, then check supported operations. For your own workflow, discuss the entry point and the action that must happen once. Ask about preparation and costs before committing.

Continue readingHow to read a workflow test receipt →
Evaluate one workflow

Can your workflow pass the same check after a failure?

Bring the entry point, dependency operations and result you need to preserve. Discuss whether AgentTwin supports the test, what preparation is needed and the scope and costs before proceeding.

Discuss your workflow Try the sample first →← Back to all articles