Skip to content

PYTHON-5767 - Finalize client backpressure implementation for phase 1…#2742

Merged
NoahStapp merged 11 commits intomongodb:backpressurefrom
NoahStapp:PYTHON-5767
Apr 13, 2026
Merged

PYTHON-5767 - Finalize client backpressure implementation for phase 1…#2742
NoahStapp merged 11 commits intomongodb:backpressurefrom
NoahStapp:PYTHON-5767

Conversation

@NoahStapp
Copy link
Copy Markdown
Contributor

@NoahStapp NoahStapp commented Mar 30, 2026

… rollout

PYTHON-5767

Changes in this PR

  • Remove all token bucket code. The initial release of client backpressure only uses backoff + jitter.
  • Remove the adaptiveRetries client knob and URI option.
  • Add two new client knobs/URI options: maxAdaptiveRetries and enableOverloadRetargeting.
  • Update changelog to include backpressure support and placeholder links for backpressure docs (DOCSP-55426 and DOCSP-57078).

Test Plan

Updated existing backpressure prose and spec tests and added new ones to comply with the final phase 1 design.

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates PyMongo’s phase-1 client backpressure behavior and tests by replacing the previous adaptiveRetries boolean with new overload-related options (maxAdaptiveRetries, enableOverloadRetargeting) and reducing the default maximum overload retry count used by tests/specs.

Changes:

  • Introduces/validates new URI + keyword options: maxAdaptiveRetries and enableOverloadRetargeting.
  • Updates retry/backpressure prose + unified JSON specs to use a lower retry limit (5 → 2) and adjusts expected command/event sequences accordingly.
  • Updates unit/integration tests to assert parsing of new options and to use the new shared retry limit constant.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/uri_options/client-backpressure-options.json URI option parsing tests updated for maxAdaptiveRetries and enableOverloadRetargeting.
test/transactions/unified/backpressure-retryable-writes.json Unified spec expectations updated for reduced backpressure retry attempts.
test/transactions/unified/backpressure-retryable-reads.json Unified spec expectations updated for reduced backpressure retry attempts.
test/transactions/unified/backpressure-retryable-commit.json Unified spec expectations updated for reduced backpressure retry attempts.
test/transactions/unified/backpressure-retryable-abort.json Unified spec expectations updated for reduced backpressure retry attempts.
test/test_client.py Client option tests updated to assert max_adaptive_retries + enable_overload_retargeting.
test/test_client_backpressure.py Backpressure tests updated to use MAX_ADAPTIVE_RETRIES and revised retry expectations.
test/client-backpressure/getMore-retried.json Spec updated for reduced retry attempts and corresponding event sequences.
test/client-backpressure/backpressure-retry-max-attempts.json Extensive spec updates to reflect reduced retry attempts across many operations.
test/client-backpressure/backpressure-retry-loop.json Spec updated for reduced retry attempts and corresponding event sequences.
test/client-backpressure/backpressure-connection-checkin.json Spec event expectations reduced to match new retry counts.
test/asynchronous/test_client.py Async client option tests updated to assert max_adaptive_retries + enable_overload_retargeting.
test/asynchronous/test_client_backpressure.py Async backpressure tests updated to use MAX_ADAPTIVE_RETRIES and revised retry expectations.
pymongo/common.py Adds defaults/constants and validators for new overload-related options.
pymongo/client_options.py Parses/stores new options and exposes new properties on ClientOptions.
pymongo/asynchronous/helpers.py Updates _RetryPolicy defaults to use MAX_ADAPTIVE_RETRIES; disables adaptive token-bucket mode.
pymongo/asynchronous/mongo_client.py Updates public docstring for new options and changes _RetryPolicy construction.
pymongo/synchronous/helpers.py Sync mirror of async helper changes (synchro-generated).
pymongo/synchronous/mongo_client.py Sync mirror of async client docstring/policy construction (synchro-generated).
Comments suppressed due to low confidence (1)

pymongo/asynchronous/helpers.py:145

  • _RetryPolicy’s docstring describes an “adaptive retries” token-bucket mode, but adaptive_retry is now hard-coded to False and there’s no longer a constructor parameter or other code path that enables it. Either reintroduce a supported way to enable the token-bucket behavior (if still intended) or update/remove the docstring and related dead code to match current behavior.
class _RetryPolicy:
    """A retry limiter that performs exponential backoff with jitter.

    When adaptive retries are enabled, retry attempts are limited by a token bucket to prevent overwhelming the server during
    a prolonged outage or high load.
    """

    def __init__(
        self,
        token_bucket: _TokenBucket,
        attempts: int = MAX_ADAPTIVE_RETRIES,
        backoff_initial: float = _BACKOFF_INITIAL,
        backoff_max: float = _BACKOFF_MAX,
    ):
        self.token_bucket = token_bucket
        self.attempts = attempts
        self.backoff_initial = backoff_initial
        self.backoff_max = backoff_max
        self.adaptive_retry = False

    async def record_success(self, retry: bool) -> None:
        """Record a successful operation."""
        if self.adaptive_retry:
            await self.token_bucket.deposit(retry)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Copy link
Copy Markdown
Contributor

@sleepyStick sleepyStick left a comment

Choose a reason for hiding this comment

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

small suggestion, feel free to veto it and otherwise approved

# Ensure command stops retrying after MAX_ADAPTIVE_RETRIES.
fail_too_many = mock_overload_error.copy()
fail_too_many["mode"] = {"times": _MAX_RETRIES + 1}
fail_too_many["mode"] = {"times": MAX_ADAPTIVE_RETRIES + 1}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

super minor comment but there's a lot of these lines where we copy the overload error and then edit the mode for the times it fails, would it be a tad easier to have a function like get_overload_error(too_many: bool) that just returns a copy of the overload error with the mode correctly set (in the function?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Something like this?

get_overload_error(times: int):
    return {"times": times}

That wouldn't reduce the repetition, just add an extra utility function that does very little. I agree that it's annoying we have 10 instances of doing almost the same assignment, but in this case we can't avoid that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

errr i think i was imagining something more like:

def get_overload_error(times: int):
    error = mock_overload_error.copy()
    error["mode"] = {"times": times}
    return error

which i think would turn the 2 lines into 1? which is still very little but yeah, up to you if you think its worth it ultimately

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right that is better, good callout!

async def test_adaptive_retries(self):
# Assert that adaptive retries are disabled by default.
async def test_max_adaptive_retries(self):
# Assert that max adaptive retries default to 2.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: "defaults to 2"

listener.reset()

# 4. Execute a `find` command with `client`.
await client.t.t.find_one({})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is t.t here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

database.collection.

Copy link
Copy Markdown
Contributor

@aclark4life aclark4life left a comment

Choose a reason for hiding this comment

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

LGTM pending nit fixes

@NoahStapp NoahStapp merged commit 02320d6 into mongodb:backpressure Apr 13, 2026
70 of 77 checks passed
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.

4 participants