diff --git a/homeassistant/core.py b/homeassistant/core.py index b9b6f729f11..8cec01ba489 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -629,6 +629,56 @@ class HomeAssistant: return task + @overload + @callback + def async_run_periodic_hass_job( + self, hassjob: HassJob[..., Coroutine[Any, Any, _R]], *args: Any + ) -> asyncio.Future[_R] | None: + ... + + @overload + @callback + def async_run_periodic_hass_job( + self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any + ) -> asyncio.Future[_R] | None: + ... + + @callback + def async_run_periodic_hass_job( + self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any + ) -> asyncio.Future[_R] | None: + """Add a periodic HassJob from within the event loop. + + This method must be run in the event loop. + hassjob: HassJob to call. + args: parameters for method to call. + """ + task: asyncio.Future[_R] + # This code path is performance sensitive and uses + # if TYPE_CHECKING to avoid the overhead of constructing + # the type used for the cast. For history see: + # https://github.com/home-assistant/core/pull/71960 + if hassjob.job_type is HassJobType.Coroutinefunction: + if TYPE_CHECKING: + hassjob.target = cast( + Callable[..., Coroutine[Any, Any, _R]], hassjob.target + ) + task = create_eager_task(hassjob.target(*args), name=hassjob.name) + elif hassjob.job_type is HassJobType.Callback: + if TYPE_CHECKING: + hassjob.target = cast(Callable[..., _R], hassjob.target) + hassjob.target(*args) + return None + else: + if TYPE_CHECKING: + hassjob.target = cast(Callable[..., _R], hassjob.target) + task = self.loop.run_in_executor(None, hassjob.target, *args) + + self._periodic_tasks.add(task) + task.add_done_callback(self._periodic_tasks.remove) + + return task + def create_task( self, target: Coroutine[Any, Any, Any], name: str | None = None ) -> None: diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index d4a3d772b5a..4975bbce486 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -1609,15 +1609,7 @@ class _TrackTimeInterval: self._track_job, hass.loop.time() + self.seconds, ) - if self._run_job.job_type is HassJobType.Coroutinefunction: - hass.async_create_periodic_task( - # mypy does not know we just checked for the job type - self.action(now), # type: ignore[arg-type] - f"track time interval {self.seconds}", - eager_start=True, - ) - else: - hass.async_run_hass_job(self._run_job, now) + hass.async_run_periodic_hass_job(self._run_job, now) @callback def async_cancel(self) -> None: