RuntimeError: The connection pool was closed while 1 HTTP requests/responses were still in-flight. #2138
-
When request cancelled, AsyncClient raise RuntimeError on exiting, httpx: both 0.22.0 and master branch Reproduce:I run into the issue when send many parallel requests, some requests may timeout, and I see the RuntimeError occasionally. Below is a simple reproduce, when task2 timeout, asyncio.gather will cancel task1, but it seems AsyncClient not proper close the request. import asyncio
import traceback
import httpx
async def task1(client: httpx.AsyncClient):
try:
return await client.get("https://httpbin.org/delay/1")
except BaseException as ex:
print("task1", type(ex), repr(ex))
traceback.print_exc()
print("-" * 60)
raise
async def task2():
# will raise asyncio.exceptions.TimeoutError in 0.5 seconds
await asyncio.wait_for(asyncio.sleep(1), 0.5)
async def main():
async with httpx.AsyncClient(timeout=10) as client:
coro1 = task1(client)
coro2 = task2()
await asyncio.gather(coro1, coro2)
if __name__ == "__main__":
asyncio.run(main()) Output:task1 <class 'asyncio.exceptions.CancelledError'> CancelledError()
Traceback (most recent call last):
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 237, in handle_async_request
response = await connection.handle_async_request(request)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/_async/http_proxy.py", line 283, in handle_async_request
stream = await stream.start_tls(**kwargs)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/backends/asyncio.py", line 72, in start_tls
raise exc
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/backends/asyncio.py", line 63, in start_tls
ssl_stream = await anyio.streams.tls.TLSStream.wrap(
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/streams/tls.py", line 100, in wrap
await wrapper._call_sslobject_method(ssl_object.do_handshake)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/streams/tls.py", line 115, in _call_sslobject_method
data = await self.transport_stream.receive()
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/_backends/_asyncio.py", line 1112, in receive
raise ClosedResourceError from None
anyio.ClosedResourceError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/kk/dev/zhuwen/httpx/http_error.py", line 9, in task1
return await client.get("https://httpbin.org/delay/1")
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1732, in get
return await self.request(
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1509, in request
return await self.send(request, auth=auth, follow_redirects=follow_redirects)
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1596, in send
response = await self._send_handling_auth(
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1624, in _send_handling_auth
response = await self._send_handling_redirects(
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1661, in _send_handling_redirects
response = await self._send_single_request(request)
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1698, in _send_single_request
response = await transport.handle_async_request(request)
File "/Users/kk/dev/zhuwen/httpx/httpx/_transports/default.py", line 353, in handle_async_request
resp = await self._pool.handle_async_request(req)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 252, in handle_async_request
await self.response_closed(status)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/_core/_synchronization.py", line 138, in acquire
await cancel_shielded_checkpoint()
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/lowlevel.py", line 57, in cancel_shielded_checkpoint
await get_asynclib().cancel_shielded_checkpoint()
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/anyio/_backends/_asyncio.py", line 464, in cancel_shielded_checkpoint
await sleep(0)
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 644, in sleep
await __sleep0()
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 633, in __sleep0
yield
asyncio.exceptions.CancelledError
------------------------------------------------------------
Traceback (most recent call last):
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 655, in sleep
return await future
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 492, in wait_for
fut.result()
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/kk/dev/zhuwen/httpx/http_error.py", line 26, in main
await asyncio.gather(coro1, coro2)
File "/Users/kk/dev/zhuwen/httpx/http_error.py", line 19, in task2
await asyncio.wait_for(asyncio.sleep(1), 0.5)
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 494, in wait_for
raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/kk/dev/zhuwen/httpx/http_error.py", line 30, in <module>
asyncio.run(main())
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Users/kk/.pyenv/versions/3.9.7/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/Users/kk/dev/zhuwen/httpx/http_error.py", line 26, in main
await asyncio.gather(coro1, coro2)
File "/Users/kk/dev/zhuwen/httpx/httpx/_client.py", line 1981, in __aexit__
await proxy.__aexit__(exc_type, exc_value, traceback)
File "/Users/kk/dev/zhuwen/httpx/httpx/_transports/default.py", line 332, in __aexit__
await self._pool.__aexit__(exc_type, exc_value, traceback)
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 326, in __aexit__
await self.aclose()
File "/Users/kk/.pyenv/versions/3.9.7/envs/httpx/lib/python3.9/site-packages/httpcore/_async/connection_pool.py", line 312, in aclose
raise RuntimeError(
RuntimeError: The connection pool was closed while 1 HTTP requests/responses were still in-flight. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
I got the reason:
The solution is manually cancel task1 before AsyncClient close. |
Beta Was this translation helpful? Give feedback.
I got the reason:
asyncio.gather
will not cancel task1 when task2 timeout, so task1 is pending when AsyncClient close. And task1 seems cancelled by asyncio loop or GC whenasyncio.run
ending.The solution is manually cancel task1 before AsyncClient close.