diff --git a/src/nwp500/auth.py b/src/nwp500/auth.py index a71f39b..fadd188 100644 --- a/src/nwp500/auth.py +++ b/src/nwp500/auth.py @@ -367,7 +367,7 @@ def __init__( async def __aenter__(self) -> "NavienAuthClient": """Async context manager entry.""" if self._owned_session: - self._session = aiohttp.ClientSession(timeout=self.timeout) + self._session = self._create_session() # Check if we have valid stored tokens if self._auth_response and self._auth_response.tokens: @@ -394,10 +394,24 @@ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: if self._owned_session and self._session: await self._session.close() + def _create_session(self) -> aiohttp.ClientSession: + """Create an aiohttp ClientSession with ThreadedResolver. + + ThreadedResolver uses Python's built-in socket module for DNS + resolution, avoiding dependency on c-ares which can fail in + containerized environments. + + Returns: + aiohttp.ClientSession configured with ThreadedResolver + """ + resolver = aiohttp.ThreadedResolver() + connector = aiohttp.TCPConnector(resolver=resolver) + return aiohttp.ClientSession(connector=connector, timeout=self.timeout) + async def _ensure_session(self) -> None: """Ensure we have an active session.""" if self._session is None: - self._session = aiohttp.ClientSession(timeout=self.timeout) + self._session = self._create_session() self._owned_session = True async def sign_in( @@ -740,8 +754,11 @@ async def refresh_access_token(refresh_token: str) -> AuthTokens: url = f"{API_BASE_URL}{REFRESH_ENDPOINT}" payload = {"refreshToken": refresh_token} + # Use ThreadedResolver for reliable DNS in containerized environments + resolver = aiohttp.ThreadedResolver() + connector = aiohttp.TCPConnector(resolver=resolver) async with ( - aiohttp.ClientSession() as session, + aiohttp.ClientSession(connector=connector) as session, session.post(url, json=payload) as response, ): response_data = await response.json()