"""Application-level shared aiohttp.ClientSession. All outgoing HTTP requests in the server package should use the shared session returned by ``get_http_session()`` instead of creating per-request ``aiohttp.ClientSession`` instances. This keeps a single TCP connection pool alive for the lifetime of the process, avoiding the overhead of pool creation/teardown on every request. Call ``close_http_session()`` once during application shutdown. """ from __future__ import annotations import asyncio import aiohttp _DEFAULT_TIMEOUT = aiohttp.ClientTimeout(total=30, connect=10) _session: aiohttp.ClientSession | None = None _lock = asyncio.Lock() async def get_http_session() -> aiohttp.ClientSession: """Get or create the shared HTTP session. Concurrent first-callers are serialized through ``_lock`` so we never leak a second ClientSession / connector pair. Once established, hot callers skip the lock via the fast-path check. """ global _session if _session is not None and not _session.closed: return _session async with _lock: if _session is None or _session.closed: _session = aiohttp.ClientSession(timeout=_DEFAULT_TIMEOUT) return _session async def close_http_session() -> None: """Close the shared HTTP session (call on app shutdown).""" global _session async with _lock: if _session is not None and not _session.closed: await _session.close() _session = None