Skip to content

Commit ce92bcf

Browse files
committed
fix pooltimeout
1 parent cacc248 commit ce92bcf

3 files changed

Lines changed: 65 additions & 9 deletions

File tree

httpcore/_async/connection_pool.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55

66
from .._backends.auto import AutoBackend
77
from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend
8-
from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol
8+
from .._exceptions import ConnectionNotAvailable, PoolTimeout, UnsupportedProtocol
99
from .._models import Origin, Request, Response
10-
from .._synchronization import AsyncEvent, AsyncLock, AsyncShieldCancellation
10+
from .._synchronization import (
11+
AsyncEvent,
12+
AsyncLock,
13+
AsyncShieldCancellation,
14+
sync_current_time,
15+
)
1116
from .connection import AsyncHTTPConnection
1217
from .interfaces import AsyncConnectionInterface, AsyncRequestInterface
1318

@@ -220,15 +225,20 @@ async def handle_async_request(self, request: Request) -> Response:
220225
)
221226

222227
status = RequestStatus(request)
228+
timeouts = request.extensions.get("timeout", {})
229+
timeout = timeouts.get("pool", None)
230+
231+
if timeout is not None:
232+
deadline = sync_current_time() + timeout
233+
else:
234+
deadline = float("inf")
223235

224236
async with self._pool_lock:
225237
self._requests.append(status)
226238
await self._close_expired_connections()
227239
await self._attempt_to_acquire_connection(status)
228240

229241
while True:
230-
timeouts = request.extensions.get("timeout", {})
231-
timeout = timeouts.get("pool", None)
232242
try:
233243
connection = await status.wait_for_connection(timeout=timeout)
234244
except BaseException as exc:
@@ -263,6 +273,10 @@ async def handle_async_request(self, request: Request) -> Response:
263273
else:
264274
break
265275

276+
timeout = deadline - sync_current_time()
277+
if timeout < 0:
278+
raise PoolTimeout
279+
266280
# When we return the response, we wrap the stream in a special class
267281
# that handles notifying the connection pool once the response
268282
# has been released.

httpcore/_sync/connection_pool.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55

66
from .._backends.sync import SyncBackend
77
from .._backends.base import SOCKET_OPTION, NetworkBackend
8-
from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol
8+
from .._exceptions import ConnectionNotAvailable, PoolTimeout, UnsupportedProtocol
99
from .._models import Origin, Request, Response
10-
from .._synchronization import Event, Lock, ShieldCancellation
10+
from .._synchronization import (
11+
Event,
12+
Lock,
13+
ShieldCancellation,
14+
sync_current_time,
15+
)
1116
from .connection import HTTPConnection
1217
from .interfaces import ConnectionInterface, RequestInterface
1318

@@ -220,15 +225,20 @@ def handle_request(self, request: Request) -> Response:
220225
)
221226

222227
status = RequestStatus(request)
228+
timeouts = request.extensions.get("timeout", {})
229+
timeout = timeouts.get("pool", None)
230+
231+
if timeout is not None:
232+
deadline = sync_current_time() + timeout
233+
else:
234+
deadline = float("inf")
223235

224236
with self._pool_lock:
225237
self._requests.append(status)
226238
self._close_expired_connections()
227239
self._attempt_to_acquire_connection(status)
228240

229241
while True:
230-
timeouts = request.extensions.get("timeout", {})
231-
timeout = timeouts.get("pool", None)
232242
try:
233243
connection = status.wait_for_connection(timeout=timeout)
234244
except BaseException as exc:
@@ -263,6 +273,10 @@ def handle_request(self, request: Request) -> Response:
263273
else:
264274
break
265275

276+
timeout = deadline - sync_current_time()
277+
if timeout < 0:
278+
raise PoolTimeout
279+
266280
# When we return the response, we wrap the stream in a special class
267281
# that handles notifying the connection pool once the response
268282
# has been released.

httpcore/_synchronization.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import threading
2+
import time
23
from types import TracebackType
3-
from typing import Optional, Type
4+
from typing import Callable, Optional, Type, Union
45

56
from ._exceptions import ExceptionMapping, PoolTimeout, map_exceptions
67

@@ -291,3 +292,30 @@ def __exit__(
291292
traceback: Optional[TracebackType] = None,
292293
) -> None:
293294
pass
295+
296+
297+
_current_time_implementation: Union[None, Callable[[], float]] = None
298+
299+
300+
def async_current_time() -> float:
301+
global _current_time_implementation
302+
303+
if not _current_time_implementation: # pragma: nocover
304+
if current_async_library() == "trio":
305+
if trio is None:
306+
raise RuntimeError(
307+
"Running with trio requires installation of 'httpcore[trio]'."
308+
)
309+
_current_time_implementation = trio.current_time
310+
else:
311+
if anyio is None:
312+
raise RuntimeError(
313+
"Running with asyncio requires installation of 'httpcore[asyncio]'."
314+
)
315+
_current_time_implementation = anyio.current_time
316+
317+
return _current_time_implementation()
318+
319+
320+
def sync_current_time() -> float:
321+
return time.monotonic()

0 commit comments

Comments
 (0)