@@ -383,7 +383,10 @@ def _truncate_metadata(metadata: MutableMapping[str, Any]) -> None:
383
383
384
384
385
385
def _raise_connection_failure (
386
- address : Any , error : Exception , msg_prefix : Optional [str ] = None
386
+ address : Any ,
387
+ error : Exception ,
388
+ msg_prefix : Optional [str ] = None ,
389
+ timeout_details : Optional [dict [str , float ]] = None ,
387
390
) -> NoReturn :
388
391
"""Convert a socket.error to ConnectionFailure and raise it."""
389
392
host , port = address
@@ -394,6 +397,8 @@ def _raise_connection_failure(
394
397
msg = f"{ host } : { error } "
395
398
if msg_prefix :
396
399
msg = msg_prefix + msg
400
+ if "configured timeouts" not in msg :
401
+ msg += format_timeout_details (timeout_details )
397
402
if isinstance (error , socket .timeout ):
398
403
raise NetworkTimeout (msg ) from error
399
404
elif isinstance (error , SSLError ) and "timed out" in str (error ):
@@ -411,6 +416,32 @@ def _cond_wait(condition: threading.Condition, deadline: Optional[float]) -> boo
411
416
return condition .wait (timeout )
412
417
413
418
419
+ def _get_timeout_details (options : PoolOptions ) -> dict [str , float ]:
420
+ details = {}
421
+ timeout = _csot .get_timeout ()
422
+ socket_timeout = options .socket_timeout
423
+ connect_timeout = options .connect_timeout
424
+ if timeout :
425
+ details ["timeoutMS" ] = timeout * 1000
426
+ if socket_timeout and not timeout :
427
+ details ["socketTimeoutMS" ] = socket_timeout * 1000
428
+ if connect_timeout :
429
+ details ["connectTimeoutMS" ] = connect_timeout * 1000
430
+ return details
431
+
432
+
433
+ def format_timeout_details (details : Optional [dict [str , float ]]) -> str :
434
+ result = ""
435
+ if details :
436
+ result += " (configured timeouts:"
437
+ for timeout in ["socketTimeoutMS" , "timeoutMS" , "connectTimeoutMS" ]:
438
+ if timeout in details :
439
+ result += f" { timeout } : { details [timeout ]} ms,"
440
+ result = result [:- 1 ]
441
+ result += ")"
442
+ return result
443
+
444
+
414
445
class PoolOptions :
415
446
"""Read only connection pool options for a MongoClient.
416
447
@@ -740,10 +771,15 @@ def apply_timeout(
740
771
rtt = self .connect_rtt
741
772
max_time_ms = timeout - rtt
742
773
if max_time_ms < 0 :
774
+ timeout_details = _get_timeout_details (self .opts )
775
+ formatted = format_timeout_details (timeout_details )
743
776
# CSOT: raise an error without running the command since we know it will time out.
744
- errmsg = f"operation would exceed time limit, remaining timeout:{ timeout :.5f} <= network round trip time:{ rtt :.5f} "
777
+ errmsg = f"operation would exceed time limit, remaining timeout:{ timeout :.5f} <= network round trip time:{ rtt :.5f} { formatted } "
745
778
raise ExecutionTimeout (
746
- errmsg , 50 , {"ok" : 0 , "errmsg" : errmsg , "code" : 50 }, self .max_wire_version
779
+ errmsg ,
780
+ 50 ,
781
+ {"ok" : 0 , "errmsg" : errmsg , "code" : 50 },
782
+ self .max_wire_version ,
747
783
)
748
784
if cmd is not None :
749
785
cmd ["maxTimeMS" ] = int (max_time_ms * 1000 )
@@ -1131,7 +1167,8 @@ def _raise_connection_failure(self, error: BaseException) -> NoReturn:
1131
1167
self .close_conn (reason )
1132
1168
# SSLError from PyOpenSSL inherits directly from Exception.
1133
1169
if isinstance (error , (IOError , OSError , SSLError )):
1134
- _raise_connection_failure (self .address , error )
1170
+ details = _get_timeout_details (self .opts )
1171
+ _raise_connection_failure (self .address , error , timeout_details = details )
1135
1172
else :
1136
1173
raise
1137
1174
@@ -1255,7 +1292,8 @@ def _configured_socket(address: _Address, options: PoolOptions) -> Union[socket.
1255
1292
# We raise AutoReconnect for transient and permanent SSL handshake
1256
1293
# failures alike. Permanent handshake failures, like protocol
1257
1294
# mismatch, will be turned into ServerSelectionTimeoutErrors later.
1258
- _raise_connection_failure (address , exc , "SSL handshake failed: " )
1295
+ details = _get_timeout_details (options )
1296
+ _raise_connection_failure (address , exc , "SSL handshake failed: " , timeout_details = details )
1259
1297
if (
1260
1298
ssl_context .verify_mode
1261
1299
and not ssl_context .check_hostname
@@ -1553,7 +1591,8 @@ def connect(self, handler: Optional[_MongoClientErrorHandler] = None) -> Connect
1553
1591
)
1554
1592
1555
1593
if isinstance (error , (IOError , OSError , SSLError )):
1556
- _raise_connection_failure (self .address , error )
1594
+ details = _get_timeout_details (self .opts )
1595
+ _raise_connection_failure (self .address , error , timeout_details = details )
1557
1596
1558
1597
raise
1559
1598
@@ -1634,7 +1673,10 @@ def _raise_if_not_ready(self, emit_event: bool) -> None:
1634
1673
self .opts ._event_listeners .publish_connection_check_out_failed (
1635
1674
self .address , ConnectionCheckOutFailedReason .CONN_ERROR
1636
1675
)
1637
- _raise_connection_failure (self .address , AutoReconnect ("connection pool paused" ))
1676
+ details = _get_timeout_details (self .opts )
1677
+ _raise_connection_failure (
1678
+ self .address , AutoReconnect ("connection pool paused" ), timeout_details = details
1679
+ )
1638
1680
1639
1681
def _get_conn (self , handler : Optional [_MongoClientErrorHandler ] = None ) -> Connection :
1640
1682
"""Get or create a Connection. Can raise ConnectionFailure."""
0 commit comments