Glossary
Idempotence: safely repeating an operation
A timeout, retry, or restarted worker must not create a second order, reservation, or payment.
Short definition
The same request may arrive several times. There should still be only one result.
Idempotence is a property of an operation, not of a particular HTTP method or database. If a service processes the same command again, it should leave the same business state after completion as after the first successful run. The goal is one local order for one marketplace order, not one order for every import attempt.
The response does not have to be identical. The first call may return 201 Created and the second 200 with the existing result; both are correct. An audit can record two received requests. What matters is that the important effect is not repeated.
Use cases
Where duplicates hurt most
Protection matters where the client cannot tell whether the previous attempt completed the work.
- orders from a marketplace or order form
- payment confirmations, inventory reservations, and refunds
- imports of products, inventory movements, and order states
- message queues with repeated delivery
- external APIs with timeouts, retries, and temporary unavailability
- scheduled jobs running on multiple instances
Practical example
Importing a marketplace order after a timeout
A marketplace sends order M-4821. The import stores it, but the response is lost, so the marketplace sends the same request again. Without protection, a second order, inventory reservation, and email would be created.
The service uses the marketplace and external_order_id combination as a stable identity. A unique constraint prevents two simultaneous writes, while the second attempt finds the existing result. If no external ID exists, the client sends an idempotency key bound to the user, operation, and input fingerprint.
How it works
From uncertain delivery to a single result
The deduplication identity must survive concurrency and process restarts.
- Operation identity The client uses an external order ID or idempotency key for one specific command.
- First processing attempt The service stores the target or operation record in a transaction; a constraint protects against concurrency.
- Timeout or retry The client repeats the request with the same identity because it does not know the outcome of the first attempt.
- Deduplication The service finds the completed or in-progress state and returns the result or processing status.
- Follow-up effects An email, payment, or another API needs its own duplicate protection.
Important features
Identity, constraints, retries, and state
One PHP check without persistent, concurrency-safe protection is not enough when two processes run at the same time.
Idempotency key
A unique client key for retrying the same command. The server must define its validity, scope, and behaviour when the same key is used with different input.
Unique constraint
For concurrent creation of the same record, a database constraint is more reliable than the “SELECT first, then INSERT” pattern.
Message deduplication
A queue consumer stores a processed message ID or business key because the message may arrive again after the worker crashes.
Retry and operation state
A retry has limited attempts and delays. The processing, completed, and failed states determine what a second request does.
Benefits and limitations
Safer retries, not a magical guarantee
Benefits
- safer retries of uncertain network requests and messages
- fewer duplicate orders, reservations, and manual corrections
- predictable client behaviour after a timeout
- a clearly named identity for the business operation
What to watch for
- a key without persistent, concurrency-safe storage does not survive a restart or parallel requests
- retaining the key for too short a time reopens the path to duplicates
- the system must not silently accept the same key with different input
- recipient idempotence is not an end-to-end exactly-once claim
Scope of use
Use it according to the cost of an error, not as a mandatory pattern.
Strong protection belongs with payments, orders, inventory reservations, imports, and concurrent jobs. The cost of a duplicate effect exceeds that of an unambiguous identity, a constraint, and tests.
For an inconsequential data read or an action that does not change state, ordinary HTTP semantics may be enough. Idempotence should not justify a complex framework; it should protect a specific risky effect.
What to keep in mind
Test the unpleasant scenarios as well
The design should be tested by simulating a lost response, concurrency, and repeated delivery.
- the first attempt, a retry, and parallel attempts
- a constraint matching the business identity
- logging the key, external ID, and result without sensitive data
- retries and a traceable process for messages that fail over the long term
- a separate strategy for effects outside the database
Common questions
What idempotence means in practice
Is POST always non-idempotent?
At the HTTP level, POST is not generally idempotent. A specific POST operation can be designed so the same idempotency key creates exactly one result.
Must the second attempt return the same HTTP response?
No. The same intended state matters. The second attempt can return the previously created resource or information that the operation is still running.
Is a Redis key with TTL enough?
It can help with short-lived coordination, but does not provide durable protection for an important order or payment. The key can disappear after expiration, an outage, or eviction.
Is idempotence the same as exactly once?
No. An idempotent recipient handles multiple deliveries with the same result. Exactly once is a stronger end-to-end claim.
How I work with integration processes in practice
For important synchronisation processes, I account for retries and uncertain outcomes.
In integration and e-commerce systems, I design imports, synchronisation, and error states so they can be safely traced and retried.