Avoid looking up the callable type for HassJob when we already know it (#102962)
* Avoid looking up the callable type for HassJob when we already know it When we connect the frontend we call async_listen with run_immediately MANY times when we already know the job type (it will always be a callback). This reduces the latency to get the frontend going * missing coverage
This commit is contained in:
parent
7dbe0c3a48
commit
b3743937de
4 changed files with 69 additions and 8 deletions
|
@ -282,11 +282,12 @@ class HassJob(Generic[_P, _R_co]):
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
*,
|
*,
|
||||||
cancel_on_shutdown: bool | None = None,
|
cancel_on_shutdown: bool | None = None,
|
||||||
|
job_type: HassJobType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a job object."""
|
"""Create a job object."""
|
||||||
self.target = target
|
self.target = target
|
||||||
self.name = name
|
self.name = name
|
||||||
self.job_type = _get_hassjob_callable_job_type(target)
|
self.job_type = job_type or _get_hassjob_callable_job_type(target)
|
||||||
self._cancel_on_shutdown = cancel_on_shutdown
|
self._cancel_on_shutdown = cancel_on_shutdown
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1153,13 +1154,20 @@ class EventBus:
|
||||||
|
|
||||||
This method must be run in the event loop.
|
This method must be run in the event loop.
|
||||||
"""
|
"""
|
||||||
|
job_type: HassJobType | None = None
|
||||||
if event_filter is not None and not is_callback_check_partial(event_filter):
|
if event_filter is not None and not is_callback_check_partial(event_filter):
|
||||||
raise HomeAssistantError(f"Event filter {event_filter} is not a callback")
|
raise HomeAssistantError(f"Event filter {event_filter} is not a callback")
|
||||||
if run_immediately and not is_callback_check_partial(listener):
|
if run_immediately:
|
||||||
raise HomeAssistantError(f"Event listener {listener} is not a callback")
|
if not is_callback_check_partial(listener):
|
||||||
|
raise HomeAssistantError(f"Event listener {listener} is not a callback")
|
||||||
|
job_type = HassJobType.Callback
|
||||||
return self._async_listen_filterable_job(
|
return self._async_listen_filterable_job(
|
||||||
event_type,
|
event_type,
|
||||||
(HassJob(listener, f"listen {event_type}"), event_filter, run_immediately),
|
(
|
||||||
|
HassJob(listener, f"listen {event_type}", job_type=job_type),
|
||||||
|
event_filter,
|
||||||
|
run_immediately,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -1234,7 +1242,11 @@ class EventBus:
|
||||||
)
|
)
|
||||||
|
|
||||||
filterable_job = (
|
filterable_job = (
|
||||||
HassJob(_onetime_listener, f"onetime listen {event_type} {listener}"),
|
HassJob(
|
||||||
|
_onetime_listener,
|
||||||
|
f"onetime listen {event_type} {listener}",
|
||||||
|
job_type=HassJobType.Callback,
|
||||||
|
),
|
||||||
None,
|
None,
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,6 +24,7 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
CALLBACK_TYPE,
|
CALLBACK_TYPE,
|
||||||
HassJob,
|
HassJob,
|
||||||
|
HassJobType,
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
State,
|
State,
|
||||||
callback,
|
callback,
|
||||||
|
@ -1376,6 +1377,7 @@ def async_track_point_in_time(
|
||||||
utc_converter,
|
utc_converter,
|
||||||
name=f"{job.name} UTC converter",
|
name=f"{job.name} UTC converter",
|
||||||
cancel_on_shutdown=job.cancel_on_shutdown,
|
cancel_on_shutdown=job.cancel_on_shutdown,
|
||||||
|
job_type=HassJobType.Callback,
|
||||||
)
|
)
|
||||||
return async_track_point_in_utc_time(hass, track_job, point_in_time)
|
return async_track_point_in_utc_time(hass, track_job, point_in_time)
|
||||||
|
|
||||||
|
@ -1531,7 +1533,10 @@ def async_track_time_interval(
|
||||||
job_name = f"track time interval {interval} {action}"
|
job_name = f"track time interval {interval} {action}"
|
||||||
|
|
||||||
interval_listener_job = HassJob(
|
interval_listener_job = HassJob(
|
||||||
interval_listener, job_name, cancel_on_shutdown=cancel_on_shutdown
|
interval_listener,
|
||||||
|
job_name,
|
||||||
|
cancel_on_shutdown=cancel_on_shutdown,
|
||||||
|
job_type=HassJobType.Callback,
|
||||||
)
|
)
|
||||||
remove = async_call_later(hass, interval_seconds, interval_listener_job)
|
remove = async_call_later(hass, interval_seconds, interval_listener_job)
|
||||||
|
|
||||||
|
@ -1703,6 +1708,7 @@ def async_track_utc_time_change(
|
||||||
pattern_time_change_listener_job = HassJob(
|
pattern_time_change_listener_job = HassJob(
|
||||||
pattern_time_change_listener,
|
pattern_time_change_listener,
|
||||||
f"time change listener {hour}:{minute}:{second} {action}",
|
f"time change listener {hour}:{minute}:{second} {action}",
|
||||||
|
job_type=HassJobType.Callback,
|
||||||
)
|
)
|
||||||
time_listener = async_track_point_in_utc_time(
|
time_listener = async_track_point_in_utc_time(
|
||||||
hass, pattern_time_change_listener_job, calculate_next(dt_util.utcnow())
|
hass, pattern_time_change_listener_job, calculate_next(dt_util.utcnow())
|
||||||
|
|
|
@ -16,7 +16,14 @@ import requests
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||||
from homeassistant.core import CALLBACK_TYPE, Event, HassJob, HomeAssistant, callback
|
from homeassistant.core import (
|
||||||
|
CALLBACK_TYPE,
|
||||||
|
Event,
|
||||||
|
HassJob,
|
||||||
|
HassJobType,
|
||||||
|
HomeAssistant,
|
||||||
|
callback,
|
||||||
|
)
|
||||||
from homeassistant.exceptions import (
|
from homeassistant.exceptions import (
|
||||||
ConfigEntryAuthFailed,
|
ConfigEntryAuthFailed,
|
||||||
ConfigEntryError,
|
ConfigEntryError,
|
||||||
|
@ -104,7 +111,11 @@ class DataUpdateCoordinator(BaseDataUpdateCoordinatorProtocol, Generic[_DataT]):
|
||||||
job_name += f" {name}"
|
job_name += f" {name}"
|
||||||
if entry := self.config_entry:
|
if entry := self.config_entry:
|
||||||
job_name += f" {entry.title} {entry.domain} {entry.entry_id}"
|
job_name += f" {entry.title} {entry.domain} {entry.entry_id}"
|
||||||
self._job = HassJob(self._handle_refresh_interval, job_name)
|
self._job = HassJob(
|
||||||
|
self._handle_refresh_interval,
|
||||||
|
job_name,
|
||||||
|
job_type=HassJobType.Coroutinefunction,
|
||||||
|
)
|
||||||
self._unsub_refresh: CALLBACK_TYPE | None = None
|
self._unsub_refresh: CALLBACK_TYPE | None = None
|
||||||
self._unsub_shutdown: CALLBACK_TYPE | None = None
|
self._unsub_shutdown: CALLBACK_TYPE | None = None
|
||||||
self._request_refresh_task: asyncio.TimerHandle | None = None
|
self._request_refresh_task: asyncio.TimerHandle | None = None
|
||||||
|
|
|
@ -816,6 +816,16 @@ async def test_eventbus_run_immediately(hass: HomeAssistant) -> None:
|
||||||
unsub()
|
unsub()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_eventbus_run_immediately_not_callback(hass: HomeAssistant) -> None:
|
||||||
|
"""Test we raise when passing a non-callback with run_immediately."""
|
||||||
|
|
||||||
|
def listener(event):
|
||||||
|
"""Mock listener."""
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
hass.bus.async_listen("test", listener, run_immediately=True)
|
||||||
|
|
||||||
|
|
||||||
async def test_eventbus_unsubscribe_listener(hass: HomeAssistant) -> None:
|
async def test_eventbus_unsubscribe_listener(hass: HomeAssistant) -> None:
|
||||||
"""Test unsubscribe listener from returned function."""
|
"""Test unsubscribe listener from returned function."""
|
||||||
calls = []
|
calls = []
|
||||||
|
@ -2534,3 +2544,25 @@ def test_is_callback_check_partial():
|
||||||
assert HassJob(ha.callback(functools.partial(not_callback_func))).job_type == (
|
assert HassJob(ha.callback(functools.partial(not_callback_func))).job_type == (
|
||||||
ha.HassJobType.Executor
|
ha.HassJobType.Executor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hassjob_passing_job_type():
|
||||||
|
"""Test passing the job type to HassJob when we already know it."""
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
def callback_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def not_callback_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert (
|
||||||
|
HassJob(callback_func, job_type=ha.HassJobType.Callback).job_type
|
||||||
|
== ha.HassJobType.Callback
|
||||||
|
)
|
||||||
|
|
||||||
|
# We should trust the job_type passed in
|
||||||
|
assert (
|
||||||
|
HassJob(not_callback_func, job_type=ha.HassJobType.Callback).job_type
|
||||||
|
== ha.HassJobType.Callback
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue