Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f66ec0f

Browse files
mongodb-dbx-release-bot[bot]blink1073
andauthored
PYTHON-5492 Fix handling of MaxTimeMS message (#2484) [v4.14] (#2485)
Co-authored-by: Steven Silvester <steven.silvester@ieee.org>
1 parent 6611bec commit f66ec0f

File tree

10 files changed

+73
-44
lines changed

10 files changed

+73
-44
lines changed

‎pymongo/asynchronous/encryption.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@
7575
NetworkTimeout,
7676
ServerSelectionTimeoutError,
7777
)
78+
from pymongo.helpers_shared import _get_timeout_details
7879
from pymongo.network_layer import async_socket_sendall
7980
from pymongo.operations import UpdateOne
8081
from pymongo.pool_options import PoolOptions
8182
from pymongo.pool_shared import (
8283
_async_configured_socket,
83-
_get_timeout_details,
8484
_raise_connection_failure,
8585
)
8686
from pymongo.read_concern import ReadConcern

‎pymongo/asynchronous/pool.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
WaitQueueTimeoutError,
5959
)
6060
from pymongo.hello import Hello, HelloCompat
61+
from pymongo.helpers_shared import _get_timeout_details, format_timeout_details
6162
from pymongo.lock import (
6263
_async_cond_wait,
6364
_async_create_condition,
@@ -79,9 +80,7 @@
7980
SSLErrors,
8081
_CancellationContext,
8182
_configured_protocol_interface,
82-
_get_timeout_details,
8383
_raise_connection_failure,
84-
format_timeout_details,
8584
)
8685
from pymongo.read_preferences import ReadPreference
8786
from pymongo.server_api import _add_to_command

‎pymongo/asynchronous/server.py‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
_SDAMStatusMessage,
3939
)
4040
from pymongo.message import _convert_exception, _GetMore, _OpMsg, _Query
41-
from pymongo.pool_shared import _get_timeout_details, format_timeout_details
4241
from pymongo.response import PinnedResponse, Response
4342

4443
if TYPE_CHECKING:
@@ -225,11 +224,7 @@ async def run_operation(
225224
if use_cmd:
226225
first = docs[0]
227226
await operation.client._process_response(first, operation.session) # type: ignore[misc, arg-type]
228-
# Append timeout details to MaxTimeMSExpired responses.
229-
if first.get("code") == 50:
230-
timeout_details = _get_timeout_details(conn.opts) # type:ignore[has-type]
231-
first["errmsg"] += format_timeout_details(timeout_details) # type:ignore[index]
232-
_check_command_response(first, conn.max_wire_version)
227+
_check_command_response(first, conn.max_wire_version, pool_opts=conn.opts) # type:ignore[has-type]
233228
except Exception as exc:
234229
duration = datetime.now() - start
235230
if isinstance(exc, (NotPrimaryError, OperationFailure)):

‎pymongo/helpers_shared.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
if TYPE_CHECKING:
4848
from pymongo.cursor_shared import _Hint
4949
from pymongo.operations import _IndexList
50+
from pymongo.pool_options import PoolOptions
5051
from pymongo.typings import _DocumentOut
5152

5253

@@ -108,6 +109,34 @@
108109
}
109110

110111

112+
def _get_timeout_details(options: PoolOptions) -> dict[str, float]:
113+
from pymongo import _csot
114+
115+
details = {}
116+
timeout = _csot.get_timeout()
117+
socket_timeout = options.socket_timeout
118+
connect_timeout = options.connect_timeout
119+
if timeout:
120+
details["timeoutMS"] = timeout * 1000
121+
if socket_timeout and not timeout:
122+
details["socketTimeoutMS"] = socket_timeout * 1000
123+
if connect_timeout:
124+
details["connectTimeoutMS"] = connect_timeout * 1000
125+
return details
126+
127+
128+
def format_timeout_details(details: Optional[dict[str, float]]) -> str:
129+
result = ""
130+
if details:
131+
result += " (configured timeouts:"
132+
for timeout in ["socketTimeoutMS", "timeoutMS", "connectTimeoutMS"]:
133+
if timeout in details:
134+
result += f" {timeout}: {details[timeout]}ms,"
135+
result = result[:-1]
136+
result += ")"
137+
return result
138+
139+
111140
def _gen_index_name(keys: _IndexList) -> str:
112141
"""Generate an index name from the set of fields it is over."""
113142
return "_".join(["{}_{}".format(*item) for item in keys])
@@ -188,6 +217,7 @@ def _check_command_response(
188217
max_wire_version: Optional[int],
189218
allowable_errors: Optional[Container[Union[int, str]]] = None,
190219
parse_write_concern_error: bool = False,
220+
pool_opts: Optional[PoolOptions] = None,
191221
) -> None:
192222
"""Check the response to a command for errors."""
193223
if "ok" not in response:
@@ -243,6 +273,10 @@ def _check_command_response(
243273
if code in (11000, 11001, 12582):
244274
raise DuplicateKeyError(errmsg, code, response, max_wire_version)
245275
elif code == 50:
276+
# Append timeout details to MaxTimeMSExpired responses.
277+
if pool_opts:
278+
timeout_details = _get_timeout_details(pool_opts)
279+
errmsg += format_timeout_details(timeout_details)
246280
raise ExecutionTimeout(errmsg, code, response, max_wire_version)
247281
elif code == 43:
248282
raise CursorNotFound(errmsg, code, response, max_wire_version)

‎pymongo/pool_shared.py‎

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
NetworkTimeout,
3737
_CertificateError,
3838
)
39+
from pymongo.helpers_shared import _get_timeout_details, format_timeout_details
3940
from pymongo.network_layer import AsyncNetworkingInterface, NetworkingInterface, PyMongoProtocol
4041
from pymongo.pool_options import PoolOptions
4142
from pymongo.ssl_support import PYSSLError, SSLError, _has_sni
@@ -149,32 +150,6 @@ def _raise_connection_failure(
149150
raise AutoReconnect(msg) from error
150151

151152

152-
def _get_timeout_details(options: PoolOptions) -> dict[str, float]:
153-
details = {}
154-
timeout = _csot.get_timeout()
155-
socket_timeout = options.socket_timeout
156-
connect_timeout = options.connect_timeout
157-
if timeout:
158-
details["timeoutMS"] = timeout * 1000
159-
if socket_timeout and not timeout:
160-
details["socketTimeoutMS"] = socket_timeout * 1000
161-
if connect_timeout:
162-
details["connectTimeoutMS"] = connect_timeout * 1000
163-
return details
164-
165-
166-
def format_timeout_details(details: Optional[dict[str, float]]) -> str:
167-
result = ""
168-
if details:
169-
result += " (configured timeouts:"
170-
for timeout in ["socketTimeoutMS", "timeoutMS", "connectTimeoutMS"]:
171-
if timeout in details:
172-
result += f" {timeout}: {details[timeout]}ms,"
173-
result = result[:-1]
174-
result += ")"
175-
return result
176-
177-
178153
class _CancellationContext:
179154
def __init__(self) -> None:
180155
self._cancelled = False

‎pymongo/synchronous/encryption.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@
7070
NetworkTimeout,
7171
ServerSelectionTimeoutError,
7272
)
73+
from pymongo.helpers_shared import _get_timeout_details
7374
from pymongo.network_layer import sendall
7475
from pymongo.operations import UpdateOne
7576
from pymongo.pool_options import PoolOptions
7677
from pymongo.pool_shared import (
7778
_configured_socket,
78-
_get_timeout_details,
7979
_raise_connection_failure,
8080
)
8181
from pymongo.read_concern import ReadConcern

‎pymongo/synchronous/pool.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
WaitQueueTimeoutError,
5656
)
5757
from pymongo.hello import Hello, HelloCompat
58+
from pymongo.helpers_shared import _get_timeout_details, format_timeout_details
5859
from pymongo.lock import (
5960
_cond_wait,
6061
_create_condition,
@@ -76,9 +77,7 @@
7677
SSLErrors,
7778
_CancellationContext,
7879
_configured_socket_interface,
79-
_get_timeout_details,
8080
_raise_connection_failure,
81-
format_timeout_details,
8281
)
8382
from pymongo.read_preferences import ReadPreference
8483
from pymongo.server_api import _add_to_command

‎pymongo/synchronous/server.py‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
_SDAMStatusMessage,
3838
)
3939
from pymongo.message import _convert_exception, _GetMore, _OpMsg, _Query
40-
from pymongo.pool_shared import _get_timeout_details, format_timeout_details
4140
from pymongo.response import PinnedResponse, Response
4241
from pymongo.synchronous.helpers import _handle_reauth
4342

@@ -225,11 +224,7 @@ def run_operation(
225224
if use_cmd:
226225
first = docs[0]
227226
operation.client._process_response(first, operation.session) # type: ignore[misc, arg-type]
228-
# Append timeout details to MaxTimeMSExpired responses.
229-
if first.get("code") == 50:
230-
timeout_details = _get_timeout_details(conn.opts) # type:ignore[has-type]
231-
first["errmsg"] += format_timeout_details(timeout_details) # type:ignore[index]
232-
_check_command_response(first, conn.max_wire_version)
227+
_check_command_response(first, conn.max_wire_version, pool_opts=conn.opts) # type:ignore[has-type]
233228
except Exception as exc:
234229
duration = datetime.now() - start
235230
if isinstance(exc, (NotPrimaryError, OperationFailure)):

‎test/asynchronous/test_cursor.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
from bson import decode_all
4545
from bson.code import Code
46+
from bson.raw_bson import RawBSONDocument
4647
from pymongo import ASCENDING, DESCENDING
4748
from pymongo.asynchronous.cursor import AsyncCursor, CursorType
4849
from pymongo.asynchronous.helpers import anext
@@ -199,6 +200,21 @@ async def test_max_time_ms(self):
199200
finally:
200201
await client.admin.command("configureFailPoint", "maxTimeAlwaysTimeOut", mode="off")
201202

203+
async def test_maxtime_ms_message(self):
204+
db = self.db
205+
await db.t.insert_one({"x": 1})
206+
with self.assertRaises(Exception) as error:
207+
await db.t.find_one({"$where": delay(2)}, max_time_ms=1)
208+
209+
self.assertIn("(configured timeouts: connectTimeoutMS: 20000.0ms", str(error.exception))
210+
211+
client = await self.async_rs_client(document_class=RawBSONDocument)
212+
await client.db.t.insert_one({"x": 1})
213+
with self.assertRaises(Exception) as error:
214+
await client.db.t.find_one({"$where": delay(2)}, max_time_ms=1)
215+
216+
self.assertIn("(configured timeouts: connectTimeoutMS: 20000.0ms", str(error.exception))
217+
202218
async def test_max_await_time_ms(self):
203219
db = self.db
204220
await db.pymongo_test.drop()

‎test/test_cursor.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
from bson import decode_all
4545
from bson.code import Code
46+
from bson.raw_bson import RawBSONDocument
4647
from pymongo import ASCENDING, DESCENDING
4748
from pymongo.collation import Collation
4849
from pymongo.errors import ExecutionTimeout, InvalidOperation, OperationFailure, PyMongoError
@@ -197,6 +198,21 @@ def test_max_time_ms(self):
197198
finally:
198199
client.admin.command("configureFailPoint", "maxTimeAlwaysTimeOut", mode="off")
199200

201+
def test_maxtime_ms_message(self):
202+
db = self.db
203+
db.t.insert_one({"x": 1})
204+
with self.assertRaises(Exception) as error:
205+
db.t.find_one({"$where": delay(2)}, max_time_ms=1)
206+
207+
self.assertIn("(configured timeouts: connectTimeoutMS: 20000.0ms", str(error.exception))
208+
209+
client = self.rs_client(document_class=RawBSONDocument)
210+
client.db.t.insert_one({"x": 1})
211+
with self.assertRaises(Exception) as error:
212+
client.db.t.find_one({"$where": delay(2)}, max_time_ms=1)
213+
214+
self.assertIn("(configured timeouts: connectTimeoutMS: 20000.0ms", str(error.exception))
215+
200216
def test_max_await_time_ms(self):
201217
db = self.db
202218
db.pymongo_test.drop()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /