Skip to content

PYTHON-5272 Implement TLS session resumption for sync pool#2864

Draft
blink1073 wants to merge 10 commits into
mongodb:masterfrom
blink1073:PYTHON-5272
Draft

PYTHON-5272 Implement TLS session resumption for sync pool#2864
blink1073 wants to merge 10 commits into
mongodb:masterfrom
blink1073:PYTHON-5272

Conversation

@blink1073

@blink1073 blink1073 commented Jun 10, 2026

Copy link
Copy Markdown
Member

PYTHON-5272

Changes in this PR

Added TLS session resumption to the connection pool, avoiding a full handshake on each new connection to the same server. Session reuse is active on the sync path unconditionally, and on the async path on Python 3.11 or later.

Test Plan

Added unit and integration tests covering:

  • _SSLSessionCache get/set behavior
  • Pool creates a session cache when TLS is configured
  • A session is stored after a successful connection
  • The cached session is passed to wrap_socket on subsequent connections (sync, no server required)
  • The cached session is set on the SSLObject before the handshake on Python 3.11+ (async, no server required)

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage? — Yes
  • Is any followup work tracked in a JIRA ticket? If so, add link(s). — Async session reuse on Python < 3.11 deferred; no separate ticket yet

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?

Add _SSLSessionCache to cache TLS sessions per pool, enabling session
resumption on subsequent connections to the same server. This avoids
full asymmetric-key handshakes on every new connection, addressing the
OpenSSL 3.0 performance overhead seen in BF-36991.
@blink1073 blink1073 requested a review from a team as a code owner June 10, 2026 11:54
@blink1073 blink1073 requested a review from sleepyStick June 10, 2026 11:54
@blink1073 blink1073 marked this pull request as draft June 10, 2026 11:56
Verify that a pre-populated _SSLSessionCache passes the cached session
as session= to wrap_socket on the next connection, using mocks so no
live server is required.
@codecov-commenter

codecov-commenter commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pymongo/pool_shared.py 88.00% 1 Missing and 5 partials ⚠️

📢 Thoughts on this report? Let us know!

On Python 3.11+, SSLProtocol.__init__ creates the ssl.SSLObject via
wrap_bio before the handshake starts in connection_made. We temporarily
replace asyncio.sslproto.SSLProtocol with a subclass that sets
sslobj.session to the cached session immediately after super().__init__,
then restore the original class. With a pre-connected sock= parameter,
_make_ssl_transport is called synchronously inside create_connection
before the first await, so the swap is race-free in a single-threaded
event loop.

After the handshake, the session is retrieved via
transport.get_extra_info('ssl_object').session and stored in the pool's
_SSLSessionCache for the next connection.
@blink1073 blink1073 removed the request for review from sleepyStick June 10, 2026 21:17
Module-level import of asyncio.sslproto on PyPy 3.11 changed GC timing
and surfaced a pre-existing unclosed-socket ResourceWarning as a test
error.  Use a module-level None sentinel instead and initialise it on
first use inside the function, which keeps the import lazy while still
capturing the true original SSLProtocol before any patching occurs.
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.

2 participants