diff --git a/pymongo/__init__.py b/pymongo/__init__.py index 9e877e9551..801d466c2e 100644 --- a/pymongo/__init__.py +++ b/pymongo/__init__.py @@ -127,8 +127,9 @@ def timeout(seconds: Optional[float]) -> ContextManager: NetworkTimeout) as exc: print(f"block timed out: {exc!r}") - When nesting :func:`~pymongo.timeout`, the nested block overrides the - timeout. When exiting the block, the previous deadline is restored:: + When nesting :func:`~pymongo.timeout`, the newly computed deadline is capped to at most + the existing deadline. The deadline can only be shortened, not extended. + When exiting the block, the previous deadline is restored:: with pymongo.timeout(5): coll.find_one() # Uses the 5 second deadline. @@ -136,7 +137,7 @@ def timeout(seconds: Optional[float]) -> ContextManager: coll.find_one() # Uses the 3 second deadline. coll.find_one() # Uses the original 5 second deadline. with pymongo.timeout(10): - coll.find_one() # Uses the 10 second deadline. + coll.find_one() # Still uses the original 5 second deadline. coll.find_one() # Uses the original 5 second deadline. :Parameters: diff --git a/pymongo/_csot.py b/pymongo/_csot.py index f1601f75d2..ddd4e9233f 100644 --- a/pymongo/_csot.py +++ b/pymongo/_csot.py @@ -70,9 +70,9 @@ def __init__(self, timeout: Optional[float]): def __enter__(self): timeout_token = TIMEOUT.set(self._timeout) - deadline_token = DEADLINE.set( - time.monotonic() + self._timeout if self._timeout else float("inf") - ) + prev_deadline = DEADLINE.get() + next_deadline = time.monotonic() + self._timeout if self._timeout else float("inf") + deadline_token = DEADLINE.set(min(prev_deadline, next_deadline)) rtt_token = RTT.set(0.0) self._tokens = (timeout_token, deadline_token, rtt_token) return self diff --git a/test/test_csot.py b/test/test_csot.py index d00f8c2916..290851159d 100644 --- a/test/test_csot.py +++ b/test/test_csot.py @@ -43,10 +43,11 @@ def test_timeout_nested(self): self.assertEqual(_csot.get_timeout(), 10) deadline_10 = _csot.get_deadline() + # Capped at the original 10 deadline. with pymongo.timeout(15): coll.find_one() self.assertEqual(_csot.get_timeout(), 15) - self.assertGreater(_csot.get_deadline(), deadline_10) + self.assertEqual(_csot.get_deadline(), deadline_10) # Should be reset to previous values self.assertEqual(_csot.get_timeout(), 10)