Unit 03.03: Actions that must not run twice
Retries and outward actions do not mix by default, and an agent that retries is the normal case.
A key derived from the run and the step
The action takes a key. If the key has been seen, the call returns the previous result instead of acting again.
The example below calls the same send three times with one key.
ACTION KEY: run-8841:notify-customer
attempt 1 no record of this key -> notice sent (msg-1)
attempt 2 key already seen -> already sent (msg-1)
attempt 3 key already seen -> already sent (msg-1)
notices actually sent: 1
The key is built from the run and the step, so every retry of that step
produces the same key. A key made from a timestamp would produce three.
Three attempts, one notice. The key is run-8841:notify-customer - derived from the run and the step, so every retry of that step produces the same key.
That construction is the part that goes wrong. A key generated inside the call, from a timestamp or a random id, makes each retry look like new work - which is precisely the bug the mechanism was added to prevent.
The mistake this prevents
The mistake is deduplicating on the arguments. Two genuinely separate notices to the same account with the same text must both go out; two retries of one must not. Only a key tied to the run distinguishes them.
Takeaway
Give every outward action an idempotency key built from the run id and the step name. Retries then become safe by construction rather than by everyone remembering.
