mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Always do thread safety check when writing state (#118886)
* Always do thread safety check when writing state Refactor the 3 most common places where the thread safety check for the event loop to be inline to make the check fast enough that we can keep it long term. While code review catches most of the thread safety issues in core, some of them still make it through, and new ones keep getting added. Its not possible to catch them all with manual code review, so its worth the tiny overhead to check each time. Previously the check was limited to custom components because they were the most common source of thread safety issues. * Always do thread safety check when writing state Refactor the 3 most common places where the thread safety check for the event loop to be inline to make the check fast enough that we can keep it long term. While code review catches most of the thread safety issues in core, some of them still make it through, and new ones keep getting added. Its not possible to catch them all with manual code review, so its worth the tiny overhead to check each time. Previously the check was limited to custom components because they were the most common source of thread safety issues. * async_fire is more common than expected with ccs * fix mock * fix hass mocking
This commit is contained in:
@@ -434,25 +434,17 @@ class HomeAssistant:
|
||||
self.import_executor = InterruptibleThreadPoolExecutor(
|
||||
max_workers=1, thread_name_prefix="ImportExecutor"
|
||||
)
|
||||
self._loop_thread_id = getattr(
|
||||
self.loop_thread_id = getattr(
|
||||
self.loop, "_thread_ident", getattr(self.loop, "_thread_id")
|
||||
)
|
||||
|
||||
def verify_event_loop_thread(self, what: str) -> None:
|
||||
"""Report and raise if we are not running in the event loop thread."""
|
||||
if self._loop_thread_id != threading.get_ident():
|
||||
if self.loop_thread_id != threading.get_ident():
|
||||
# frame is a circular import, so we import it here
|
||||
from .helpers import frame # pylint: disable=import-outside-toplevel
|
||||
|
||||
# frame is a circular import, so we import it here
|
||||
frame.report(
|
||||
f"calls {what} from a thread other than the event loop, "
|
||||
"which may cause Home Assistant to crash or data to corrupt. "
|
||||
"For more information, see "
|
||||
"https://developers.home-assistant.io/docs/asyncio_thread_safety/"
|
||||
f"#{what.replace('.', '')}",
|
||||
error_if_core=True,
|
||||
error_if_integration=True,
|
||||
)
|
||||
frame.report_non_thread_safe_operation(what)
|
||||
|
||||
@property
|
||||
def _active_tasks(self) -> set[asyncio.Future[Any]]:
|
||||
@@ -793,16 +785,10 @@ class HomeAssistant:
|
||||
|
||||
target: target to call.
|
||||
"""
|
||||
# We turned on asyncio debug in April 2024 in the dev containers
|
||||
# in the hope of catching some of the issues that have been
|
||||
# reported. It will take a while to get all the issues fixed in
|
||||
# custom components.
|
||||
#
|
||||
# In 2025.5 we should guard the `verify_event_loop_thread`
|
||||
# check with a check for the `hass.config.debug` flag being set as
|
||||
# long term we don't want to be checking this in production
|
||||
# environments since it is a performance hit.
|
||||
self.verify_event_loop_thread("hass.async_create_task")
|
||||
if self.loop_thread_id != threading.get_ident():
|
||||
from .helpers import frame # pylint: disable=import-outside-toplevel
|
||||
|
||||
frame.report_non_thread_safe_operation("hass.async_create_task")
|
||||
return self.async_create_task_internal(target, name, eager_start)
|
||||
|
||||
@callback
|
||||
@@ -1497,7 +1483,10 @@ class EventBus:
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
_verify_event_type_length_or_raise(event_type)
|
||||
self._hass.verify_event_loop_thread("hass.bus.async_fire")
|
||||
if self._hass.loop_thread_id != threading.get_ident():
|
||||
from .helpers import frame # pylint: disable=import-outside-toplevel
|
||||
|
||||
frame.report_non_thread_safe_operation("hass.bus.async_fire")
|
||||
return self.async_fire_internal(
|
||||
event_type, event_data, origin, context, time_fired
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user