Skip to content

Implement the overload retry policy for commands that are read/write retryable - #2041

Draft
stIncMale wants to merge 11 commits into
mongodb:backpressurefrom
stIncMale:overloadRetryPolicyForCommandsThatAreRWRetryable_real
Draft

Implement the overload retry policy for commands that are read/write retryable#2041
stIncMale wants to merge 11 commits into
mongodb:backpressurefrom
stIncMale:overloadRetryPolicyForCommandsThatAreRWRetryable_real

Conversation

@stIncMale

@stIncMale stIncMale commented Aug 18, 2026

Copy link
Copy Markdown
Member

VAKOTODO Run tests on Evergreen and self-review with Claude before asking or review:

  • The only new test failure is CrudProseTest.testBulkWriteHandlesCursorRequiringGetMoreWithinTransaction (both sync and async).

This PR was originally drafted as stIncMale#4.

Also add `UnifiedClientBackpressureTest` and enable prose tests

JAVA-6248
- Removed `ClientSessionImpl.applyMajorityWriteConcernToTransactionOptions`, which was used in `withTransaction`. This is not the place for this logic, and it furthermore was useless, as `CommitTransactionOperation.getRetryCommandModifier` does the same, and more.
- Made `ClientSessionImpl` and `ClientSessionPublisherImpl` compute `alreadyCommitted` the same way.
- Made `ClientSessionImpl.commitTransaction` and `ClientSessionPublisherImpl.commitTransaction` handle `transactionState` and `commitInProgress` the same way.
- Passed `OperationContext` instead of `TimeoutContext` to `AbortTransactionOperation.getRetryCommandModifier`

JAVA-6248
@stIncMale stIncMale self-assigned this Aug 18, 2026
@stIncMale
stIncMale force-pushed the overloadRetryPolicyForCommandsThatAreRWRetryable_real branch 2 times, most recently from f5fab08 to 15fc28b Compare August 19, 2026 00:46
…Operation.getRetryCommandModifier` adding `withW("majority")` when not needed

JAVA-6248
@stIncMale
stIncMale force-pushed the overloadRetryPolicyForCommandsThatAreRWRetryable_real branch from 15fc28b to f6fabe4 Compare August 19, 2026 18:28
@stIncMale
stIncMale requested a review from vbabanin August 19, 2026 18:29
* @param attemptNumber attempt number > 0
* @return The calculated backoff in milliseconds.
*/
public static long calculateBackoffMs(final double baseMs, final double maxMs, final double growth, final int attemptNumber) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO Make private.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 9e447d5.

} else if (policies.containsKey(Descriptor.READ)) {
maxRetries = Descriptor.READ.maxRetries;
} else if (policies.containsKey(Descriptor.OVERLOAD)) {
maxRetries = overload().map(State.Overload::getMaxAttempts).orElse(Descriptor.OVERLOAD.maxRetries);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO Assert overload() returns non-empty Optional, because policies are never empty (see assertValid).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 85f1df5.

Comment on lines +543 to +547
int getMaxAttempts() {
return maxAttempts(maxAdaptiveRetriesSetting == null
? IndividualPolicies.Descriptor.OVERLOAD.maxRetries
: maxAdaptiveRetriesSetting);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO The getMaxAttempts method is called to compute maxRetries in IndividualPolicies.getMaxAttempts, which is then converted to max attempts again via maxAttempts(maxRetries). This is wrong.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f677474.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vbabanin Create a ticket on refactoring BaseClientSessionImpl and its subclasses (ClientSessionImpl, ClientSessionPublisherImpl):

  • We need to reduce the state and code duplication between subclasses.
  • We need to split this god object into multiple objects each implemented by a different class responsible for its own area. BaseClientSessionImpl.OverloadRetryPolicyState (BaseClientSessionImpl.overloadRetryPolicyState) is a precedent of the new state and logic being put in separate classes, and BaseClientSessionImpl being composed of their instances.

void closeCommitScope();

/**
* A part of {@link DefaultOverloadRetryPolicyState} restricted to the execution of a command

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO DefaultOverloadRetryPolicyState -> OverloadRetryPolicyState

Throwable prospectiveFailedResult = prospectiveFailedResult();
if (attemptFailedResult instanceof Error) {
onAttemptFatalFailure(policy, prospectiveFailedResult, (Error) attemptFailedResult);
policy.onAttemptFatalFailure();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO Remove policy.onAttemptFatalFailure();

}
// this `RetryControl` must not be mutated before calling `onAttemptFailure`
Decision decision = onAttemptFailure(policy, this, prospectiveFailedResult(), attemptFailedResult);
Throwable prospectiveFailedResult = prospectiveFailedResult();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAKOTODO Use getProspectiveFailedResult().orElse(null).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant