Retries and Idempotency
Retry is a step attribute, not a tag.
<step id="charge" retry="3" retry-backoff="exponential" retry-delay="1s" retry-max-delay="30s">
<script>...</script>
</step>retry is the total attempt count from 1 through 10. Backoff is fixed or exponential; exponential uses multiplier two without jitter.
Only a definitive script-thrown failure retries automatically. Timeout, invalid JSON, oversized results, crashes, interruption, and cancellation fail closed.
Use attempt.idempotencyKey with external APIs that explicitly support idempotency. The key stays stable across attempts of one logical step. A retry does not prove an interrupted external effect never happened.
Configure a bounded retry
<step
id="createCustomer"
retry="4"
retry-backoff="exponential"
retry-delay="1s"
retry-max-delay="10s"
>
<script>
const response = await services.http.request({
method: "POST",
url: "https://api.example.com/customers",
json: context.payload,
idempotency: {
header: "Idempotency-Key",
value: attempt.idempotencyKey
}
}, { name: "create-customer" });
return response.data;
</script>
</step>retry="4" means at most four total attempts, not four retries after the first attempt. Fixed backoff repeats one delay. Exponential backoff doubles from the initial delay up to the maximum and currently adds no jitter.
Understand what retries
Only a definitive thrown-script failure retries automatically. Timeout, invalid JSON, oversized output, host or worker crash, interrupted ambiguity, and cancellation fail closed because repeating them may be unsafe or meaningless.
Use attempt.number for diagnostics and attempt.maxAttempts for context. Do not create a different external idempotency identity for every attempt; attempt.idempotencyKey intentionally remains stable for the logical step.
Idempotency is an external contract
WOML can provide a stable key and reattach to managed outcomes. The external API must still document how it stores and handles repeated keys. Without that contract, a retry may create duplicate charges, messages, or records.
Prefer natural idempotency where possible, such as upserting by a stable business ID. Never assume event sourcing alone makes arbitrary side effects exactly once.