mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(custom_httpx): resolve aiohttp transport type without importing in finalizer paths
The function-level import of LiteLLMAiohttpTransport in _dispose_wrapped_aiohttp_session() and _aiohttp_session_bound_elsewhere() always raises ImportError when AsyncHTTPHandler.__del__ runs during interpreter shutdown (sys.meta_path is already None). The bare except Exception: pass in __del__ swallows it, so the disposal silently never happens and the wrapped aiohttp ClientSession/TCPConnector fire "Unclosed client session"/"Unclosed connector" warnings at GC - exactly what the disposal was written to prevent. Hoisting the import to module scope is not viable (circular import via aiohttp_transport -> secret_managers.main -> caching -> gcs_bucket_base -> http_handler during litellm/__init__). Instead, both methods already hold the live transport instance, so resolve the type from the runtime class name and skip the import entirely.
This commit is contained in:
parent
ecdc0f9ab9
commit
76a17d937e
1 changed files with 16 additions and 10 deletions
|
|
@ -1135,12 +1135,15 @@ class AsyncHTTPHandler:
|
|||
def _aiohttp_session_bound_elsewhere(self, loop: asyncio.AbstractEventLoop) -> bool:
|
||||
"""True when the wrapped aiohttp session is bound to a loop other than
|
||||
``loop`` — awaiting ``aclose()`` here would touch that loop's internals."""
|
||||
from litellm.llms.custom_httpx.aiohttp_transport import (
|
||||
LiteLLMAiohttpTransport,
|
||||
)
|
||||
|
||||
# 2026-10-24 patch 0006: class-name check instead of isinstance -- the
|
||||
# original function-level import always raises ImportError when the
|
||||
# handler is GC'd during interpreter shutdown (sys.meta_path is already
|
||||
# None), which silently aborted the disposal inside __del__'s bare
|
||||
# except and let aiohttp fire "Unclosed client session"/"Unclosed
|
||||
# connector" warnings at GC. The instance is in hand, so its runtime
|
||||
# class carries all the information isinstance needed.
|
||||
transport: Final = getattr(self._client, "_transport", None)
|
||||
if not isinstance(transport, LiteLLMAiohttpTransport):
|
||||
if type(transport).__name__ != "LiteLLMAiohttpTransport":
|
||||
return False
|
||||
session: Final = transport.client
|
||||
if not isinstance(session, ClientSession) or session.closed:
|
||||
|
|
@ -1158,12 +1161,15 @@ class AsyncHTTPHandler:
|
|||
"Unclosed client session" / "Unclosed connector" warnings fire at
|
||||
garbage collection.
|
||||
"""
|
||||
from litellm.llms.custom_httpx.aiohttp_transport import (
|
||||
LiteLLMAiohttpTransport,
|
||||
)
|
||||
|
||||
# 2026-10-24 patch 0006: class-name check instead of the function-level
|
||||
# import -- that import always raises ImportError when this runs during
|
||||
# interpreter shutdown (sys.meta_path is already None), silently
|
||||
# aborting the disposal inside __del__'s bare except and leaving the
|
||||
# wrapped aiohttp session to fire "Unclosed client session" /
|
||||
# "Unclosed connector" warnings at GC. The instance is in hand, so its
|
||||
# runtime class carries all the information isinstance needed.
|
||||
transport: Final = getattr(self._client, "_transport", None)
|
||||
if not isinstance(transport, LiteLLMAiohttpTransport):
|
||||
if type(transport).__name__ != "LiteLLMAiohttpTransport":
|
||||
return
|
||||
# A shared session (e.g. the proxy's) is never this handler's to close.
|
||||
if not getattr(transport, "_owns_session", False):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue