fix(sdk): classify Unavailable errors as side-effect free for retries - #694
Open
detail-app[bot] wants to merge 1 commit into
Open
Conversation
Contributor
|
PR author is not in the allowed authors list. |
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.
Detail bug report: View on Detail
Closes #691
Bug
ErrorCode::Unavailablewas classified as side-effecting (has_no_side_effects() == false), but every server-side use of this code maps fromStreamerMissingInActionError, which is raised before the append is submitted to the streamer actor (at lease acquisition or message-send time) — so no mutation could have occurred.The impact: clients using
AppendRetryPolicy::NoSideEffectswould not retry a unary append that receivedUnavailableafter the request body had already been sent (frame signal set). The retry logic falls back toerr.has_no_side_effects(), which returnedfalse, so the safe retry was blocked. This contradicts the inline comments inlite/src/handlers/v1/error.rs("Unavailable error code promised to be side-effect free").Fix
Move
ErrorCode::Unavailablefrom thefalsebranch to thetruebranch ofErrorCode::has_no_side_effects()inapi/src/v1/error.rs. This matches the documented intent and the streamer backend's own internal retry behavior (backend/core.rsalready retries onStreamerMissingInActionError).The contrasting
RequestDroppedError(which occurs after submission, where a mutation may have taken effect) continues to map toErrorCode::Otherand remain side-effecting — unchanged.Testing
api/src/v1/error.rsthat requires everyErrorCodevariant to be explicitly classified as side-effecting or side-effect free, guarding against future silent misclassifications as the#[non_exhaustive]enum evolves.Unavailableserver error is both retryable and side-effect free through theServerError/AppendErrorsurfaces.NoSideEffectsretry-policy test to cover the core bug scenario: a signalled frame signal (body sent) +Unavailableerror must now be safe to retry.s2-api(49) ands2-sdk(106),s2-litebackend/streamer/handler tests (225), clippy (default features), andcargo +nightly fmt --all --check.End-to-end verification
Started a local
s2-liteserver (s2 lite --port 4243) and ran the SDK integration test suite using the same scoping as CI (cargo test -p s2-sdk --all-features -- --skip access_token --skip metrics): 77 tests pass, 0 failed, confirming no regression in append/read/list flows.The unfiltered integration run has 26 pre-existing failures (all
501 not_implementedfrom the lite server for metrics and access-token-management endpoints); verified identical on the baseline before this change viagit stash.Not verified
The exact race window — a streamer actor exiting mid-request after guard acquisition but before the append acks — was not reproduced end-to-end. The streamer's 60s dormancy timeout and the lack of an internal shutdown hook in the black-box SDK integration harness make it non-deterministic to trigger at a precise point. The verifiable core of the bug (the retry decision under a signalled frame signal +
Unavailable) is covered by the extended unit test.Automatic Fixes PRs can be configured here.