Exactly-Once Effect Semantics

Exactly-once business effects require coordination beyond merely retrying an HTTP request because distributed systems may execute the same operation more than once. The goal is to ensure that retries and duplicate deliveries do not produce duplicate externally visible business outcomes.

A distributed request can be processed successfully even when the caller never receives the response. The caller then retries, so the server may execute the same logical operation multiple times. Network failures, timeouts, client retries, message redelivery, and service crashes can all create this situation.

Idempotency is a common building block. A client supplies a stable idempotency key representing one logical operation, and the server records that key together with the operation's result. A repeated request with the same key can then return the recorded result instead of performing the business operation again.

The difficult part is atomicity. The system must prevent a race where two requests with the same key both observe that no record exists and both perform the side effect. Typically, the idempotency record and the business state are coordinated in one transactional storage operation, or the side effect is designed around another mechanism that provides equivalent deduplication guarantees.

Exactly-once effect semantics is narrower than claiming that a distributed system executes code exactly once. Code can run twice, and messages can be delivered more than once. What matters is that the intended business effect, such as creating one payment or one order, is committed at most once for a given logical operation while successful retries can recover the same outcome.

The design also needs a policy for ambiguous states. If a process crashes after committing the business transaction but before recording or returning the response, a later retry must be able to discover the committed result. Conversely, an idempotency key should not be reused for a different logical request, and retention must last long enough to cover the retry and duplicate-delivery window.

Key points

Interview questions

Why doesn't retrying an HTTP request automatically provide exactly-once behavior?

A request can reach the server and complete successfully even if the response is lost. The client then cannot distinguish that situation from a request that never executed and may retry it. If the operation is non-idempotent, the retry can create a second business effect. An idempotency mechanism lets the server recognize the retry and return the existing result.

How would you implement an idempotent create-order API?

Require the client to send a unique idempotency key for each logical order creation. Persist that key together with the resulting order identifier and relevant response data. Enforce uniqueness on the key and coordinate the insertion with order creation so concurrent requests cannot create two orders. A retry with the same key should return the previously committed result.

What failure occurs if the idempotency check and business write are separate transactions?

A race can occur between the check and the business write. Two requests may both observe that the key is absent and then both perform the business operation. A process crash can also leave the business state committed while the idempotency record is missing, causing a later retry to repeat the effect. The design therefore needs atomic coordination or a recovery mechanism that makes the committed business result discoverable.

Does exactly-once effect semantics mean the handler executes exactly once?

No. The handler may execute multiple times because retries and redelivery are normal in distributed systems. The guarantee concerns the durable business result rather than the number of executions. For example, two deliveries may reach a consumer, but only one order should be committed for the same logical operation.

How would you handle an external side effect that cannot participate in your database transaction?

A local transaction cannot atomically commit both the database and an unrelated external system. A common approach is an outbox pattern: commit the business state and an event describing the required external action in one local transaction, then deliver that event reliably. The external consumer should itself support idempotency or deduplication, usually using a stable operation identifier. This changes the design from trying to achieve one distributed atomic transaction to composing durable, retry-safe steps.