Conversation
This resolves Home Assistant warnings about blocking calls to open() inside the event loop. The AWS IoT SDK performs synchronous file I/O operations when reading metadata files during connection setup. Changes: - Wrap mqtt_connection_builder.websockets_with_default_aws_signing() in executor - Move credentials provider creation into the executor - Add documentation explaining why executor is needed Fixes Home Assistant warning: 'Detected blocking call to open with args (...awsiotsdk...METADATA) inside the event loop by custom integration' This is a non-breaking change that maintains full API compatibility.
Contributor
There was a problem hiding this comment.
Pull Request Overview
This PR addresses a blocking I/O warning in Home Assistant by moving synchronous AWS IoT SDK connection setup off the event loop.
- Wraps MQTT connection and credential provider creation in a thread executor to avoid blocking.
- Adds inline comments explaining the rationale for the executor use.
Replace the custom nested _build_connection + run_in_executor pattern with asyncio.to_thread() for clearer intent and better performance: - Uses asyncio.to_thread() for credentials provider creation - Uses asyncio.to_thread() for connection builder call - Avoids redefining functions on every connect() call - More explicit about threading blocking operations - Uses current event loop implicitly - Cleaner, more readable code This is the modern Python 3.9+ approach for handling blocking operations in async code.
Owner
Author
🔄 Improved ImplementationI've updated the implementation based on feedback to use ✨ Improvements Made
📋 ChangesBefore: def _build_connection():
credentials_provider = self._create_credentials_provider()
return mqtt_connection_builder.websockets_with_default_aws_signing(...)
self._connection = await self._loop.run_in_executor(None, _build_connection)After: credentials_provider = await asyncio.to_thread(self._create_credentials_provider)
self._connection = await asyncio.to_thread(
mqtt_connection_builder.websockets_with_default_aws_signing,
endpoint=self.config.endpoint,
region=self.config.region,
credentials_provider=credentials_provider,
# ... other args
)✅ Testing
The implementation is now cleaner, more efficient, and follows modern Python async best practices! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Home Assistant was detecting blocking calls to
open()inside the event loop when the MQTT client attempted to connect, causing this warning:The issue occurs because the AWS IoT SDK performs synchronous file I/O operations when reading metadata files during connection setup in
mqtt_connection_builder.websockets_with_default_aws_signing().Solution
This PR wraps the blocking connection setup operations in an asyncio executor to avoid blocking the main event loop. The changes are:
Wrapped connection setup in executor: The
mqtt_connection_builder.websockets_with_default_aws_signing()call and credential provider creation now run in a thread pool viaasyncio.run_in_executor()Moved credential creation into executor: The
_create_credentials_provider()call is now inside the executor function to ensure all potentially blocking operations are isolatedAdded clear documentation: Comments explain why the executor is needed and what operations are being protected
Changes Made
NavienMqttClient.connect()method insrc/nwp500/mqtt_client.pyBenefits
Testing
run_in_executoris properly called during connection setupType of Change
References