|
47 | 47 | if TYPE_CHECKING: |
48 | 48 | from pymongo.cursor_shared import _Hint |
49 | 49 | from pymongo.operations import _IndexList |
| 50 | + from pymongo.pool_options import PoolOptions |
50 | 51 | from pymongo.typings import _DocumentOut |
51 | 52 |
|
52 | 53 |
|
|
108 | 109 | } |
109 | 110 |
|
110 | 111 |
|
| 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 | + |
111 | 140 | def _gen_index_name(keys: _IndexList) -> str: |
112 | 141 | """Generate an index name from the set of fields it is over.""" |
113 | 142 | return "_".join(["{}_{}".format(*item) for item in keys]) |
@@ -188,6 +217,7 @@ def _check_command_response( |
188 | 217 | max_wire_version: Optional[int], |
189 | 218 | allowable_errors: Optional[Container[Union[int, str]]] = None, |
190 | 219 | parse_write_concern_error: bool = False, |
| 220 | + pool_opts: Optional[PoolOptions] = None, |
191 | 221 | ) -> None: |
192 | 222 | """Check the response to a command for errors.""" |
193 | 223 | if "ok" not in response: |
@@ -243,6 +273,10 @@ def _check_command_response( |
243 | 273 | if code in (11000, 11001, 12582): |
244 | 274 | raise DuplicateKeyError(errmsg, code, response, max_wire_version) |
245 | 275 | 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) |
246 | 280 | raise ExecutionTimeout(errmsg, code, response, max_wire_version) |
247 | 281 | elif code == 43: |
248 | 282 | raise CursorNotFound(errmsg, code, response, max_wire_version) |
|
0 commit comments