Monotonic settlement for shared durable operation records
When retries share one durable operation record, replace last-write-wins with a monotonic merge so committed success cannot be overwritten by later timeout or unknown observations.
Monotonic settlement for shared durable operation records
When to use
Multiple client retries share one durable operation record keyed by an idempotency key. Attempts can finish in either order: one may observe committed success while another later times out. Naive last-write-wins settlement can overwrite completed with unknown and discard the stored result.
Core rule
Separate canonical operation outcome from per-attempt observations.
- The canonical record holds the authoritative status and immutable committed result.
- Each attempt may log its own terminal observation, but attempt logs must not blindly overwrite the canonical record.
Settlement is monotonic merge, not last-write-wins.
Status lattice
Assign each status an ordinal rank (higher wins on conflict):
pending/running— in flightunknown— caller lost the response; effect may or may not have committedfailed— committed failure (terminal)completed— committed success with stored result (terminal, absorbing)
Rules:
- Never downgrade from
completedorfailedbecause of a weaker observation. - Always upgrade to
completedwhen durable evidence shows the effect committed, even ifunknownwas written first. - Store the result atomically in the same write that transitions to
completed; treat it as immutable afterward.
Settlement writes
Use conditional updates (compare-and-set on status rank), for example:
- Write
unknownonly if current status rank is belowunknown. - Write
completedplus result if current status is not alreadycompleted. - If already
completed, ignore duplicate success or late timeout writes.
Optional: keep a settled_at or monotonic outcome_version for audit, but do not use wall-clock write time to pick the winner across unequal evidence types.
Order A: success first, timeout second
- Attempt A commits effect and writes canonical record:
completed+ result. - Attempt B times out and tries to write
unknown. - Conditional guard rejects the downgrade; canonical record stays
completed. - Attempt B should read the canonical record (poll or on retry) and return the stored result.
Order B: timeout first, success second
- Attempt B times out and writes
unknownon the canonical record (allowed while not yet completed). - Attempt A commits and writes
completed+ result. - Upgrade succeeds because
completedoutranksunknown. - Any caller reading the record sees success; no duplicate effect if execution is idempotent under the same key.
Client contract
- Timeout means response unknown, not failure.
- After timeout, re-read the durable record or retry with the same idempotency key.
- Do not treat a local timeout as permission to issue a new logical operation under a fresh key.
What to verify in tests (not design reasoning)
- Concurrent settlement: success then timeout leaves
completedunchanged. - Concurrent settlement: timeout then success ends at
completedwith result present. - Result field never cleared after first successful commit.
- Duplicate retries after completion replay the stored outcome without re-running the effect.