Skip to content

fix: reuse httpx.AsyncClient to prevent blocking SSL calls#1

Closed
Teraformerrr wants to merge 1 commit intofingltd:mainfrom
Teraformerrr:fix/reuse-httpx-client-prevent-blocking-ssl
Closed

fix: reuse httpx.AsyncClient to prevent blocking SSL calls#1
Teraformerrr wants to merge 1 commit intofingltd:mainfrom
Teraformerrr:fix/reuse-httpx-client-prevent-blocking-ssl

Conversation

@Teraformerrr
Copy link
Copy Markdown

What does this PR do?

Reuses a single httpx.AsyncClient instance instead of creating a new one per API call.

Problem

Each call to get_devices(), get_contacts(), or get_agent_info() creates a new httpx.AsyncClient(). Every new client initializes a fresh SSL context, which calls ssl.SSLContext.load_verify_locations() — a synchronous blocking I/O operation that reads certificate files from disk.

When used inside an async event loop (e.g., Home Assistant), this blocks the entire event loop and causes:

  • Detected blocking call to load_verify_locations warnings
  • Integration failures and timeouts

Related Home Assistant issues:

Changes

  • Lazily create and reuse a single httpx.AsyncClient across all requests
  • Add close() method for proper client cleanup
  • Add __aenter__ / __aexit__ for async context manager support
  • Fully backward compatible

Each API call previously created a new httpx.AsyncClient(), which
initializes a new SSL context and calls load_verify_locations() - a
blocking I/O operation. When used inside an async event loop (such as
Home Assistant), this blocks the entire loop and causes timeouts.

This fix reuses a single AsyncClient instance across requests, adds
a close() method for cleanup, and adds async context manager support.
@Lorenzo-Gasparini
Copy link
Copy Markdown
Collaborator

Hi @Teraformerrr , thanks for opening this PR and for the detailed analysis of the SSL blocking issue!

You were spot on, creating a new AsyncClient per request was causing the event loop to block on load_verify_locations(). We've just shipped v1.1.0 which addresses this along with several other fixes. Our approach is slightly different: instead of managing the client lifecycle internally, we now accept an optional httpx.AsyncClient parameter in the constructor:

FingAgent(ip, port, key, client=get_async_client(hass))
This way Home Assistant can inject its own shared client (which already handles SSL init in an executor), while standalone usage still works without passing one.

I'm going to close this PR since the fix is already in, but really appreciate you taking the time to diagnose the root cause and reference the HA issues (home-assistant/core#164052, home-assistant/core#156513). That context was very helpful!

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