Skip to content

Fix DNS resolution in containerized environments using ThreadedResolver#35

Merged
eman merged 2 commits intomainfrom
fix/dns-resolution-threaded-resolver
Nov 15, 2025
Merged

Fix DNS resolution in containerized environments using ThreadedResolver#35
eman merged 2 commits intomainfrom
fix/dns-resolution-threaded-resolver

Conversation

@eman
Copy link
Copy Markdown
Owner

@eman eman commented Nov 15, 2025

Problem

DNS resolution failures in containerized environments (Home Assistant, Docker, Kubernetes):

  • aiohttp defaults to aiodns resolver when none specified
  • aiodns depends on c-ares C binding not reliably available in containers
  • Causes errors: aiodns.error.DNSError: (3, 'DNS server returned general failure')
  • System tools work fine, but Python async DNS fails

Solution

Use ThreadedResolver explicitly for all aiohttp.ClientSession creations:

  • ThreadedResolver uses Python's built-in socket module
  • No external c-ares dependency
  • Works reliably across all environments

Changes

  • src/nwp500/auth.py:
    • NavienAuthClient.__aenter__(): Use ThreadedResolver for session creation
    • NavienAuthClient._ensure_session(): Use ThreadedResolver for backup session
    • refresh_access_token(): Use ThreadedResolver for temporary session

Technical Details

  • Minimal changes: 13 lines added, 3 lines removed
  • No new dependencies (ThreadedResolver already in aiohttp)
  • No breaking changes
  • Fully backward compatible

Verification

✓ Linting: All checks passed (ruff format, ruff check)
✓ Syntax: Python compilation successful
✓ Runtime: ThreadedResolver successfully created in all scenarios
✓ No new type errors introduced

Impact

  • ✅ Fixes DNS failures in Home Assistant and other containers
  • ✅ No performance impact
  • ✅ No new dependencies
  • ✅ Fully backward compatible

- Replace default aiodns resolver with explicit ThreadedResolver
- Uses Python's built-in socket module instead of c-ares binding
- Fixes DNS failures in Home Assistant and other containers
- No additional dependencies required
- Minimal changes to 3 session creation points:
  * NavienAuthClient.__aenter__()
  * NavienAuthClient._ensure_session()
  * refresh_access_token() function

Resolves DNS errors: 'DNS server returned general failure'
Makes library work reliably in all containerized environments
@eman eman requested a review from Copilot November 15, 2025 21:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes DNS resolution failures in containerized environments (Home Assistant, Docker, Kubernetes) by explicitly using aiohttp's ThreadedResolver instead of relying on the default aiodns resolver, which depends on the c-ares C binding that may not be available in containers.

Key changes:

  • Replace default DNS resolution with ThreadedResolver in all aiohttp.ClientSession creations
  • ThreadedResolver uses Python's built-in socket module, eliminating external dependencies
  • All three session creation points in auth.py are updated for consistency

Comment on lines +370 to +374
resolver = aiohttp.ThreadedResolver()
connector = aiohttp.TCPConnector(resolver=resolver)
self._session = aiohttp.ClientSession(
connector=connector, timeout=self.timeout
)
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resolver and connector creation pattern is duplicated in three locations (aenter, _ensure_session, refresh_access_token). Consider extracting this into a helper method like _create_session() to reduce code duplication and make future changes easier to maintain.

Copilot uses AI. Check for mistakes.
- Add _create_session() helper method to NavienAuthClient
- Eliminates code duplication across 3 session creation points
- Improves maintainability and makes future changes easier
- All 3 locations now use single source of truth for DNS resolver config
- Maintains same functionality with cleaner code
@eman
Copy link
Copy Markdown
Owner Author

eman commented Nov 15, 2025

Update: Code Refactoring Applied ✨

Thanks for the suggestion! I've refactored the code to eliminate duplication:

Changes:

  • Added helper method to NavienAuthClient
  • Refactored all 3 session creation points to use this single helper
  • Eliminates code duplication and improves maintainability

Before (3 duplicate blocks):

resolver = aiohttp.ThreadedResolver()
connector = aiohttp.TCPConnector(resolver=resolver)
self._session = aiohttp.ClientSession(
    connector=connector, timeout=self.timeout
)

After (single source of truth):

def _create_session(self) -> aiohttp.ClientSession:
    """Create session with ThreadedResolver for reliable DNS."""
    resolver = aiohttp.ThreadedResolver()
    connector = aiohttp.TCPConnector(resolver=resolver)
    return aiohttp.ClientSession(connector=connector, timeout=self.timeout)

Updated commit: ca1773c

  • Still passes all linting checks
  • Maintains same functionality
  • Easier to maintain going forward

@eman eman merged commit 95d0a81 into main Nov 15, 2025
10 checks passed
@eman eman deleted the fix/dns-resolution-threaded-resolver branch November 15, 2025 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants