Closed Thrasher2020 closed 3 months ago
Thanks for bringing this to my attention. The fix will have to wait until Mid next week, as I am currently traveling.
It appears that the HA core team pulled another fast one on me with the 06 release like they did with the 05 release. This integration has been working fine since it was released, and now they are starting to enforce checks for updating state in the event loop! Should be an easy fix. Will keep you posted..
Thanks - enjoy your holiday :)
@bdraco
I'm running into an issue with the HA 2024.6 release, specifically trying to call async_update_entry
from a thread not on the event loop. I now understand that updating a config entry must be done in the event loop thread, as there is no sync API to update config entries. I am now trying to use hass.add_job
to schedule a function in the event loop that calls hass.config_entries.async_update_entry
.
The problem I am having is passing a keyword argument to the async_update_entry
method - old call looks like this:
session.hass.config_entries.async_update_entry(
session.config_entry,
data={**session.config_entry.data, "token": token}
)
I am trying to replace it with the following:
session.hass.add_job(
session.hass.config_entries.async_update_entry,
session.config_entry,
data={**session.config_entry.data, "token": token}
)
The replaced code is generating the following exception (logged in the System log) when trying to execute:
Error doing job: Exception in callback ConfigEntries.async_update_entry(<ConfigEntry ...xfrmd4bpfhqke>, {'auth_implementation': 'spotifyplus_...6ecc68097a218', 'description': '(Premium account)', 'id': 'xxxxxx', 'name': 'Todd L', ...})
Traceback (most recent call last):
File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
TypeError: ConfigEntries.async_update_entry() takes 2 positional arguments but 3 were given
Is there a way to pass keyword arguments to the hass.add_job
method?
Renamed the thread to better reflect the underlying error. I am back from vacation, and working on a fix for this issue.
You can use functools.partial
You can use functools.partial
@bdraco That seemed to do the trick - thank you so much!
Make sure the job you are running is wrapped in @callback
or it will run in the executor
Make sure the job you are running is wrapped in
@callback
or it will run in the executor @bdraco It is calling theasync_update_entry
, which is marked with a@callback
:@callback def async_update_entry( self, entry: ConfigEntry, *, data: Mapping[str, Any] | UndefinedType = UNDEFINED, minor_version: int | UndefinedType = UNDEFINED, options: Mapping[str, Any] | UndefinedType = UNDEFINED, pref_disable_new_entities: bool | UndefinedType = UNDEFINED, pref_disable_polling: bool | UndefinedType = UNDEFINED, title: str | UndefinedType = UNDEFINED, unique_id: str | None | UndefinedType = UNDEFINED, version: int | UndefinedType = UNDEFINED, ) -> bool: if entry.entry_id not in self._entries: raise UnknownEntry(entry.entry_id)
self.hass.verify_event_loop_thread("hass.config_entries.async_update_entry")
Thanks again for your assistance.
@Thrasher2020 Fixed with release v1.0.20 of the SpotifyPlus integration
Give it a try and let me know if you have issues. Thanks.
Testing right now. Will let you know :)
Thank you.
Make sure the job you are running is wrapped in
@callback
or it will run in the executor
@bdraco
Just curious - are there performance (or multi-threading) consequences to running a job in the executor, versus the @callback
method? Any HA documentation that I could look at to learn more about the differences or when to use one over the other?
It seems to be running fine with the @callback
method, but I have other methods that I am calling that all use the await hass.async_add_executor_job(...)
syntax. I think I have to use that syntax in these cases, as they are calls to underlying API's that do not support async, but not sure.
I appreciate your help and guidance.
hass.add_job
is generally the way to get back to the async (main thread). - as long as its decorated with @callback
https://github.com/home-assistant/core/blob/8c025ea1f7f254251d5d63f436b6da27363c83e4/homeassistant/core.py#L580
https://github.com/home-assistant/core/blob/8c025ea1f7f254251d5d63f436b6da27363c83e4/homeassistant/core.py#L745
await hass.async_add_executor_job
is generally the way to offload work that would block the event loop to another thread. There is a limit to 64 executor jobs running at the same time. It also needs to create a future, and schedule it on the other thread, wait for the result, and safely return it to the main thread so there is some additional cost for doing so which sometimes is even more expensive than the work being done.
Ideally everything is async and runs in the main thread and you don't have the overhead of switching between threads since the cost of doing it safely can comparatively be rather high for short/non-cpu bound operations. Also if everything is async you don't have to worry about thread-safety issues, only asyncio problems.
Thanks for that explanation.
Unfortunately, the underlying API’s that I am interfacing with do not support async operations. It sounds like I am stuck executing those types of operations with the async_add_executor_job.
Any functions I write in the HA integration can be written with async and decorated with @callback to make them more efficient.
Please correct me if I’m wrong on those assumptions.
Thanks for that explanation.
Unfortunately, the underlying API’s that I am interfacing with do not support async operations. It sounds like I am stuck executing those types of operations with the async_add_executor_job.
In that case I generally make a new asyncio python package, but thats likely more than you want to do.
Any functions I write in the HA integration can be written with async and decorated with @callback to make them more efficient.
There is a cost to jumping between threads so if you are already in another thread and the work you are doing is thread safe, its best not to jump back into the event loop thread unless the work needs to explicitly do something that would not be thread safe unless it ran in the event loop thread (like working with asyncio primitives)
Please correct me if I’m wrong on those assumptions.
Testing right now. Will let you know :)
Thank you.
I can confirm everything is working as before now. Thanks :)
Good to hear - closing the issue. Thanks
System Health details
System Information
Home Assistant Community Store
GitHub API | ok -- | -- GitHub Content | ok GitHub Web | ok GitHub API Calls Remaining | 5000 Installed Version | 1.34.0 Stage | running Available Repositories | 1478 Downloaded Repositories | 72 HACS Data | okHome Assistant Cloud
logged_in | true -- | -- subscription_expiration | 17 June 2024 at 01:00 relayer_connected | true relayer_region | eu-central-1 remote_enabled | true remote_connected | true alexa_enabled | true google_enabled | true remote_server | eu-central-1-10.ui.nabu.casa certificate_status | ready instance_id | 7a6e260cca76465b8d6c48b7497998f9 can_reach_cert_server | ok can_reach_cloud_auth | ok can_reach_cloud | okHome Assistant Supervisor
host_os | Home Assistant OS 12.3 -- | -- update_channel | beta supervisor_version | supervisor-2024.05.2 agent_version | 1.6.0 docker_version | 25.0.5 disk_total | 228.5 GB disk_used | 36.1 GB healthy | true supported | true host_connectivity | true supervisor_connectivity | true ntp_synchronized | true virtualization | board | rpi4-64 supervisor_api | ok version_api | ok installed_addons | Samba share (12.3.1), Grafana (10.0.0), File editor (5.8.0), TasmoAdmin (0.30.2), InfluxDB (5.0.0), Advanced SSH & Web Terminal (18.0.0), Home Assistant Google Drive Backup (0.112.1), Zigbee2MQTT (1.37.1-1), chrony (3.0.1), UniFi Network Application (3.0.5), Nginx Proxy Manager (1.0.1), Tailscale (0.19.1), PS5 MQTT (1.3.3), ESPHome (2024.5.4), Mosquitto broker (6.4.1), Glances (0.21.1), AppDaemon (0.16.6), Increase Swap (1.1.3), SQLite Web (4.1.2), MQTT Explorer (browser-1.0.3)Dashboards
dashboards | 9 -- | -- resources | 34 views | 22 mode | storageRecorder
oldest_recorder_run | 27 May 2024 at 09:06 -- | -- current_recorder_run | 30 May 2024 at 08:27 estimated_db_size | 2213.37 MiB database_engine | sqlite database_version | 3.44.2Solcast PV Forecast
can_reach_server | ok -- | -- used_requests | 3 rooftop_site_count | 1Sonoff
version | 3.7.3 (e240aaf) -- | -- cloud_online | 0 / 2 local_online | 1 / 1SpotifyPlus
integration_version | v1.0.19 -- | -- clients_configured | 1: Neil Brownlee (premium) api_endpoint_reachable | okChecklist
Describe the issue
HA2024.6.0b1 - errors reported when trying to use the integration. Log below.
Reproduction steps
...
Debug logs
Diagnostics dump
No response