From e7f3a466da4fe3cf1de4f3628f15eefee22e7d93 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 14 May 2024 10:21:51 +0900 Subject: [PATCH] more docs --- docs/asyncio_thread_safety.md | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/docs/asyncio_thread_safety.md b/docs/asyncio_thread_safety.md index 372068da..aff70b42 100644 --- a/docs/asyncio_thread_safety.md +++ b/docs/asyncio_thread_safety.md @@ -15,18 +15,51 @@ Be sure to enable [`asyncio` debug mode](https://docs.python.org/3/library/async You may have reached this page because Home Assistant detected and reported a thread safety error. Beginning in version 2024.5.0, Home Assistant can detect, report, and block some non-threaded operations to prevent system instability. Before Home Assistant could detect these errors, they may have led to unexpected restarts or undefined behaviors, as they can corrupt the internal asyncio state. Below are some tips on how to correct non-threaded operations. -### hass.async_create_task +### Ensuring code is run in the correct thread + +### Built-in helpers that take a callback + +When using Home Assistant's built-in helpers such as `event.async_track_state_change_event` or `event.track_state_change_event`, it's important to call the correct API based on which thread the code runs in. If the code runs in a thread other than the event loop, use the non-`async` version. + +In the below example, everything will run in the event loop thread, and when `async_track_state_change_event` fires, +`async_update_event_state_callback` will also be run in the event loop thread because it is decorated with `@callback`. If the `@callback` decorator is missing, `async_update_event_state_callback` would be run in the executor, which would make a non-thread-safe call to `async_write_ha_state.` + +```python + + async def async_added_to_hass(self) -> None: + """Entity has been added to hass.""" + self.async_on_remove( + async_track_state_change_event( + self.hass, + ["light.other"], + self.async_update_event_state_callback, + ) + ) + + @callback + def async_update_event_state_callback(self, event: Event[EventStateChangedData]) -> None: + """Call when entity state changes.""" + new_state = event.data["new_state"] + if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN): + return + self.async_write_ha_state() + +``` + +### Specific API calls + +#### hass.async_create_task When creating a task from a thread other than the event loop thread, instead use `hass.create_task` -### hass.bus.async_fire +#### hass.bus.async_fire When firing an event from a thread other than the event loop thread, instead use `hass.bus.fire` -### hass.services.async_register +#### hass.services.async_register When registering a services from a thread other than the event loop thread, instead use `hass.services.register` -### hass.services.async_remove +#### hass.services.async_remove When removing a services from a thread other than the event loop thread, instead use `hass.services.remove` \ No newline at end of file