fix(statewrite): classify the branch-ref-CAS 409 as a conflict so concurrent writes retry - #535
Merged
Conversation
…current writes retry The Contents API returns two 409 shapes for a rejected optimistic state write: a blob If-Match mismatch carrying 'does not match', and a branch-ref-CAS failure reading like 'is at X but expected Y' with no 'does not match'. classifyPutError and IsConflict both gated the whole conflict test behind a 'does not match' check, so the 'is at' branch was unreachable and a branch-ref-CAS 409 was returned as a fatal error. Two component finalizes racing one trunk branch produce exactly that shape, so promote, hotfix, and rollback hard-failed on the first concurrent-write 409 with zero re-apply retries. Classify on the status marker instead: require a 409 or Conflict, and accept either the 'does not match' or the 'is at' body. Applied identically to both functions so the typed path and the forwarded-error fallback agree. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
cascade's optimistic state-write retry was defeated for the real concurrent-writer conflict shape. The Contents API returns two 409 shapes: a blob If-Match mismatch carrying
does not match, and a branch-ref compare-and-swap failure reading likeis at X but expected Ywith nodoes not match. BothclassifyPutErrorandIsConflictgated the whole conflict test behind adoes not matchcheck, so theis atbranch was unreachable dead code and a branch-ref-CAS 409 was returned as a fatal error.Two component finalizes racing one trunk branch produce exactly that shape, so promote, hotfix, and rollback hard-failed on the first concurrent-write 409 with zero re-apply retries. This affects adopters running concurrent lifecycle operations on a busy trunk.
Fix
Classify on the status marker: require a
409orConflict, and accept either thedoes not matchor theis atbody. Applied identically toclassifyPutErrorandIsConflictso the typed path and the forwarded-error fallback agree. Conservative: a non-409/Conflict error is still never classified as a conflict.Verification
New tests (red before, green after): a branch-ref-CAS 409 body classifies as a conflict via both functions;
CommitWithRetrynow re-fetches and re-applies on that shape instead of hard-failing; a non-conflict error is not classified. Existingdoes not matchblob-shape cases untouched.go build,go test ./... -race,golangci-lintall clean.