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
{{ message }}
Repository navigation
[Deduplicated] on Marten: a concurrent [WriteAggregate] repeat gets a 500, not the 409, when its commit fails on the stream version first #5166
Wolverine 6.51.3, Wolverine.Http, Marten integration, PostgreSQL. Found while aligning #5161 with GH-4505.
What happens
GH-4505 queues the [Deduplicated] claim on the Marten session, and RefuseDuplicateClaimAtCommitFrame turns the one duplicate an optimistic check can't catch, two concurrent requests that both read "not claimed", into the endpoint's 409. Its exception filter, MartenDeduplicationFailures.IsDuplicateDeduplicationClaim, matches only a unique violation on the deduplication table.
On a [WriteAggregate] endpoint, both concurrent requests load the stream at the same version and both append. Marten fails the second commit on the stream version before it reaches the claim's INSERT, so the filter never matches. The loser's EventStreamUnexpectedMaxEventIdException escapes as a 500. The work is still done only once, so this is about the answer, not duplicate work.
Reproduction
Two concurrent requests with the same Idempotency-Key, held at a barrier inside the endpoint so both have loaded the stream before either appends:
Host: MessageDeduplicationMode.CompareByHash, AutoApplyTransactions(), Marten with IntegrateWithWolverine(). The generated code has the GH-4505 frames (QueueClaim, the IsDuplicateDeduplicationClaim filter).
An application using MapMartenConcurrencyFailuresToConflict() will see a 409 anyway, from that policy instead of from deduplication.
Possible fix
What #5161 does for [DeduplicatedWithResponse(ClaimInTransaction = true)]: wrap only the commit, and on any failure check whether the key is now claimed. If it is, answer with the refusal; if not, rethrow unaltered. A marker after the commit keeps later failures out. A claim committed meanwhile can only come from a concurrent request with the same key, so answering from it is right whatever the commit failed on.
Activity
GH-5160, GH-5165, GH-5166: [DeduplicatedWithResponse] ClaimInTransact…