Pinned migration-recipient retry backoff and recovery boundaries
Parent: Chunk migration commit, range deleter and orphan cleanup internals · Published reference · snapshot 2026-11-02
↓ Facts as markdownall context files
Source-anchored research for Pinned migration-recipient retry backoff and recovery boundaries. Run status: COMPLETED.
These notes link each claim to its source. Some citations identify archived research reports that are no longer hosted on this site. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
How it works
- The real caller constructs a `CancelableOperationContext` from a newly made client operation context, the cancellation token and the fixed executor, grants internal authorization when authentication is enabled, and uses `opCtx->sleepFor(delay)`. Its `PrimaryOnlyServiceRetryStrategy` uses `kAlwaysRetryPredicate`; the source comment motivates backoff for persistent errors such as `NotWritablePrimary` until stepdown cancellation or writability. (low confidence) [source]
- The header broadly lists explicit abort among cancellation causes. In the implementation, `abort` returns without changing state if no session exists and rejects a mismatched session. On its remaining path, and in `abortWithoutSessionIdCheck`, cancellation occurs only when `_state < kCommitStart`; the method then sets `kAbort` and notifies waiters. The source comment explains that interrupting critical-section acquisition at or after `kCommitStart` can leave an uncleared recovery document. (medium confidence) [source 1] [source 2]
Problems, failure modes and limitations
- After the retry-document gate, the caller installs the logical session id and transaction number, checks out the session, and calls `txnParticipant.beginOrContinue`. It invokes `_recoverMigration` when `skipToCritSecTaken || isRetry`, otherwise `_migrateDriver`. Its error callback calls `_setStateFail` before the helper evaluates cancellation or retry policy. (low confidence) [source]
- The `StopsWhenCanceled` fixture cancels the loop token inside the first attempt and throws `InterruptedDueToReplStateChange`. It asserts one attempt, zero sleeps, one matching error callback, and no recorded strategy failures. (low confidence) [source]
- The `StopsWhenRetryStrategyGivesUp` fixture sets the retry limit to two, always throws `NotWritablePrimary`, and asserts three attempts, two sleeps, three recorded failures and zero successes. (low confidence) [source]
- The production retry strategy builds `DefaultRetryStrategy` from server retry parameters after setting `base.maxRetryAttempts` to `std::numeric_limits<std::int32_t>::max()`. Its failure method delegates to the underlying strategy, increments the jitter attempt count and calls the transient callback only when that result permits retry, and otherwise calls the unrecoverable callback. The next delay is the maximum of the underlying delay and jitter delay. Success, targeting metadata and backoff accounting delegate to the underlying strategy. (medium confidence) [source 1] [source 2]
Comparisons and alternatives
- The fixtures use `FakeRetryStrategy`, which returns a fixed delay, appends failures and backoffs, increments successes, and permits retry while the failure count is at most `_maxRetries`. Their operation contexts use `CancellationToken::uncancelable()`; cancellation of the separately supplied loop token is exercised explicitly, rather than through token-bound fixture contexts. (low confidence) [source]
Facts and statements
- In the pinned helper, each loop iteration calls `makeOpCtx` before entering the `try` block. The first iteration has `isRetry = false`, so it calls `attempt` without querying the retry delay; a normal return records success and returns. (medium confidence) [source 1] [source 2]
- The helper header says it calls sleep before every retry. In the implementation, `retryStrategy.getNextRetryDelay` selects the retry delay; only a value greater than `Milliseconds{0}` invokes `sleep` on the new attempt context, followed by `retryStrategy.recordBackoff`. Zero or negative delays invoke neither callback. (low confidence) [source 1] [source 2]
- The catch block converts the exception to a status and calls `onError` before checking cancellation. Cancellation short-circuits `retryStrategy.recordFailureAndEvaluateShouldRetry`; otherwise that strategy decision determines whether the loop returns or creates another context. (low confidence) [source]
- The catch block surrounds delay selection, sleeping, backoff accounting, the attempt and success accounting. Context creation occurs outside it, and `onError` runs inside the catch handler; neither location is covered by that same catch. The helper has no unconditional cancellation check before the first attempt. (low confidence) [source]
- On a retry, the real attempt first checks `migrationRecipientRecoveryDocumentExists` and returns immediately if absent. The predicate counts recipient recovery documents in `kMigrationRecipientsNamespace` whose migration-session-id field matches `sessionId.toString()`, and tests whether the count is greater than zero. This early return reaches the helper success path without invoking recovery. (low confidence) [source]
- `restoreRecoveredMigrationState` waits for an existing migration thread outside the mutex, restores fields from the recovery document, sets `kCommitStart`, and starts `_migrateThread` with the skip-to-critical-section argument true. That initial recovery attempt has its retry flag false, so the retry-only document-existence gate does not run on it. (low confidence) [source]
- The `FirstAttemptSucceedsWithoutSleeping` fixture asserts one attempt flagged false, no sleeps, errors or failures, and one success. (low confidence) [source]
- The `BacksOffBeforeEachRetry` fixture throws `NotWritablePrimary` twice, then asserts attempt flags false/true/true, two sleeps of 100 milliseconds, matching recorded backoffs, two matching errors/failures, and one success. Its sleep callback checks that backoff accounting has not yet advanced for that sleep. (low confidence) [source]
- The `SleepsOnTheOperationContextOfTheNextAttempt` fixture asserts two attempts and that the sleep context equals the final attempt context; it does not assert that context pointer addresses differ across attempts. (low confidence) [source]
- The `DoesNotSleepWhenDelayIsZero` fixture uses a zero delay and asserts two attempts, zero sleeps and an empty backoff vector. (low confidence) [source]
- The `StopsWhenSleepIsInterrupted` fixture first throws `NotWritablePrimary` from an attempt, then cancels the token and throws `CallbackCanceled` from sleep. It asserts one attempt, two errors with cancellation last, and no recorded backoff. (low confidence) [source]
- The command documentation describes `stopShardDraining` as stopping draining intent and returning the shard to rebalance participation. At the pinned source, the helper takes the config-shards DDL lock and delegates to `stopDrain`. These passages do not establish the outcome of an already-running recipient migration or connect this command to the recipient retry token. (medium confidence) (verified as of 2026-11-02) [source 1] [source 2]
Children
- No children recorded.