You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(api): claim idempotency keys before state mutations (#385)
Plan 006. The Idempotency-Key flow on state PUT/DELETE was read-then-
mutate-then-store: two concurrent requests with the same key could both
miss the initial read, both run the mutation (each appending a
state_events row), and then silently lose the second idempotency record
to INSERT OR IGNORE. Idempotency only protected sequential retries, not
the concurrent-retry case (client timeout + retry racing the original)
it exists for.
Replace readIdempotency/storeIdempotency with claim-first functions:
claimIdempotency atomically inserts a pending row (INSERT ... ON
CONFLICT DO NOTHING) before the mutation runs, so exactly one concurrent
request becomes the writer; losers replay the completed response, hit
409 IDEMPOTENCY_CONFLICT on a hash mismatch (unchanged), or 409
IDEMPOTENCY_IN_FLIGHT if the winner hasn't finished yet.
completeIdempotency fills in the real response after a successful
mutation; releaseIdempotencyClaim deletes the pending row if the
mutation fails, so a client retry isn't stuck behind a dead claim.
Route handlers wrap the mutation in try/finally so any failure path
(service error or thrown exception) releases the claim.
Co-authored-by: duyetbot <bot@duyet.net>
0 commit comments