PYTHON-5529 Introduce optin setting to await for MinPoolSize population (#2664)

This commit is contained in:
Steven Silvester 2025-12-23 06:43:32 -06:00 committed by GitHub
parent 6ccaae5772
commit 18c1f142b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 164 additions and 60 deletions

View File

@ -2398,7 +2398,7 @@ class TestExhaustCursor(AsyncIntegrationTest):
client = self.async_rs_or_single_client()
self.addCleanup(client.close)
coll = client.pymongo_test.test
pool = async_get_pool(client)
pool = async_get_pool(client) # type:ignore
# Patch the pool to delay the connect method.
def delayed_connect(*args, **kwargs):

View File

@ -329,6 +329,17 @@ class EntityMapUtil:
kwargs["h"] = uri
client = await self.test.async_rs_or_single_client(**kwargs)
await client.aconnect()
# Wait for pool to be populated.
if "awaitMinPoolSizeMS" in spec:
pool = await async_get_pool(client)
t0 = time.monotonic()
while True:
if (time.monotonic() - t0) > spec["awaitMinPoolSizeMS"] * 1000:
raise ValueError("Test timed out during awaitMinPoolSize")
async with pool.lock:
if len(pool.conns) + pool.active_sockets >= pool.opts.min_pool_size:
break
await asyncio.sleep(0.1)
self[spec["id"]] = client
return
elif entity_type == "database":
@ -463,7 +474,7 @@ class UnifiedSpecTestMixinV1(AsyncIntegrationTest):
a class attribute ``TEST_SPEC``.
"""
SCHEMA_VERSION = Version.from_string("1.25")
SCHEMA_VERSION = Version.from_string("1.26")
RUN_ON_LOAD_BALANCER = True
TEST_SPEC: Any
TEST_PATH = "" # This gets filled in by generate_test_classes
@ -1551,7 +1562,6 @@ class UnifiedSpecTestMeta(type):
if re.search(fail_pattern, description):
test_method = unittest.expectedFailure(test_method)
break
setattr(cls, test_name, test_method)

View File

@ -28,25 +28,25 @@ from inspect import iscoroutinefunction
from bson.son import SON
from pymongo import AsyncMongoClient
from pymongo.asynchronous.pool import Pool, _CancellationContext, _PoolGeneration
from pymongo.errors import ConfigurationError
from pymongo.hello import HelloCompat
from pymongo.lock import _async_create_lock
from pymongo.operations import _Op
from pymongo.read_preferences import ReadPreference
from pymongo.server_selectors import any_server_selector, writable_server_selector
from pymongo.synchronous.pool import _CancellationContext, _PoolGeneration
_IS_SYNC = False
async def async_get_pool(client):
async def async_get_pool(client: AsyncMongoClient) -> Pool:
"""Get the standalone, primary, or mongos pool."""
topology = await client._get_topology()
server = await topology._select_server(writable_server_selector, _Op.TEST)
return server.pool
async def async_get_pools(client):
async def async_get_pools(client: AsyncMongoClient) -> list[Pool]:
"""Get all pools."""
return [
server.pool

View File

@ -1,6 +1,6 @@
{
"description": "timeoutMS behaves correctly during command execution",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4.7",
@ -69,8 +69,10 @@
"appName": "reduceMaxTimeMSTest",
"w": 1,
"timeoutMS": 500,
"heartbeatFrequencyMS": 500
"heartbeatFrequencyMS": 500,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"observeEvents": [
"commandStartedEvent"
]
@ -185,8 +187,10 @@
"appName": "rttTooHighTest",
"w": 1,
"timeoutMS": 10,
"heartbeatFrequencyMS": 500
"heartbeatFrequencyMS": 500,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"observeEvents": [
"commandStartedEvent"
]
@ -316,8 +320,10 @@
"appName": "reduceMaxTimeMSTest",
"w": 1,
"timeoutMS": 90,
"heartbeatFrequencyMS": 100000
"heartbeatFrequencyMS": 100000,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"observeEvents": [
"commandStartedEvent"
]

View File

@ -1,6 +1,6 @@
{
"description": "timeoutMS behaves correctly for the withTransaction API",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4",
@ -21,8 +21,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 500
"timeoutMS": 500,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"

View File

@ -1,6 +1,6 @@
{
"description": "MaxTimeMSExpired server errors are transformed into a custom timeout error",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.0",
@ -26,8 +26,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"

View File

@ -1,6 +1,6 @@
{
"description": "timeoutMS can be configured on a MongoClient",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4",
@ -38,8 +38,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -217,8 +219,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -390,8 +394,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -569,8 +575,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -762,8 +770,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -941,8 +951,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -1120,8 +1132,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -1305,8 +1319,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -1484,8 +1500,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -1663,8 +1681,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -1842,8 +1862,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2021,8 +2043,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2194,8 +2218,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2375,8 +2401,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2554,8 +2582,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2733,8 +2763,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -2906,8 +2938,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3079,8 +3113,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3258,8 +3294,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3441,8 +3479,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3628,8 +3668,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3807,8 +3849,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -3986,8 +4030,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -4171,8 +4217,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -4360,8 +4408,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -4549,8 +4599,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -4728,8 +4780,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -4913,8 +4967,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -5102,8 +5158,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -5297,8 +5355,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -5482,8 +5542,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"
@ -5677,8 +5739,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 250
"timeoutMS": 250,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"

View File

@ -1,6 +1,6 @@
{
"description": "timeoutMS behaves correctly for non-tailable cursors",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4"
@ -17,8 +17,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 200
"timeoutMS": 200,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"

View File

@ -1,6 +1,6 @@
{
"description": "timeoutMS behaves correctly for retryable operations",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.0",
@ -26,8 +26,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 100
"timeoutMS": 100,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent"

View File

@ -1,6 +1,6 @@
{
"description": "runCursorCommand",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4"
@ -16,6 +16,10 @@
{
"client": {
"id": "commandClient",
"uriOptions": {
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent",

View File

@ -1,6 +1,6 @@
{
"description": "sessions inherit timeoutMS from their parent MongoClient",
"schemaVersion": "1.9",
"schemaVersion": "1.26",
"runOnRequirements": [
{
"minServerVersion": "4.4",
@ -21,8 +21,10 @@
"client": {
"id": "client",
"uriOptions": {
"timeoutMS": 500
"timeoutMS": 500,
"minPoolSize": 1
},
"awaitMinPoolSizeMS": 10000,
"useMultipleMongoses": false,
"observeEvents": [
"commandStartedEvent",

View File

@ -2353,7 +2353,7 @@ class TestExhaustCursor(IntegrationTest):
client = self.rs_or_single_client()
self.addCleanup(client.close)
coll = client.pymongo_test.test
pool = get_pool(client)
pool = get_pool(client) # type:ignore
# Patch the pool to delay the connect method.
def delayed_connect(*args, **kwargs):

View File

@ -328,6 +328,17 @@ class EntityMapUtil:
kwargs["h"] = uri
client = self.test.rs_or_single_client(**kwargs)
client._connect()
# Wait for pool to be populated.
if "awaitMinPoolSizeMS" in spec:
pool = get_pool(client)
t0 = time.monotonic()
while True:
if (time.monotonic() - t0) > spec["awaitMinPoolSizeMS"] * 1000:
raise ValueError("Test timed out during awaitMinPoolSize")
with pool.lock:
if len(pool.conns) + pool.active_sockets >= pool.opts.min_pool_size:
break
time.sleep(0.1)
self[spec["id"]] = client
return
elif entity_type == "database":
@ -462,7 +473,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
a class attribute ``TEST_SPEC``.
"""
SCHEMA_VERSION = Version.from_string("1.25")
SCHEMA_VERSION = Version.from_string("1.26")
RUN_ON_LOAD_BALANCER = True
TEST_SPEC: Any
TEST_PATH = "" # This gets filled in by generate_test_classes
@ -1536,7 +1547,6 @@ class UnifiedSpecTestMeta(type):
if re.search(fail_pattern, description):
test_method = unittest.expectedFailure(test_method)
break
setattr(cls, test_name, test_method)

View File

@ -34,19 +34,19 @@ from pymongo.lock import _create_lock
from pymongo.operations import _Op
from pymongo.read_preferences import ReadPreference
from pymongo.server_selectors import any_server_selector, writable_server_selector
from pymongo.synchronous.pool import _CancellationContext, _PoolGeneration
from pymongo.synchronous.pool import Pool, _CancellationContext, _PoolGeneration
_IS_SYNC = True
def get_pool(client):
def get_pool(client: MongoClient) -> Pool:
"""Get the standalone, primary, or mongos pool."""
topology = client._get_topology()
server = topology._select_server(writable_server_selector, _Op.TEST)
return server.pool
def get_pools(client):
def get_pools(client: MongoClient) -> list[Pool]:
"""Get all pools."""
return [
server.pool