Allow passing an optional name to async_track_time_interval (#90244)

* Allow passing an optional name to async_track_time_interval

This is the same idea as passing a name to asyncio.create_task which
makes it easier to track down bugs

* more

* short

* still cannot find it

* add a few more

* test
This commit is contained in:
J. Nick Koston 2023-03-25 04:11:14 -10:00 committed by GitHub
parent 52a94dd2ac
commit 02ef7d445d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 79 additions and 17 deletions

View file

@ -27,7 +27,9 @@ async def async_setup(hass: HomeAssistant, _: ConfigType) -> bool:
async_call_later(hass, 900, analytics.send_analytics)
# Send every day
async_track_time_interval(hass, analytics.send_analytics, INTERVAL)
async_track_time_interval(
hass, analytics.send_analytics, INTERVAL, "analytics daily"
)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, start_schedule)

View file

@ -38,7 +38,7 @@ class AugustSubscriberMixin:
def _async_setup_listeners(self):
"""Create interval and stop listeners."""
self._unsub_interval = async_track_time_interval(
self._hass, self._async_refresh, self._update_interval
self._hass, self._async_refresh, self._update_interval, "august refresh"
)
@callback

View file

@ -98,7 +98,10 @@ class BaseHaScanner(ABC):
self._start_time = self._last_detection = MONOTONIC_TIME()
if not self._cancel_watchdog:
self._cancel_watchdog = async_track_time_interval(
self.hass, self._async_scanner_watchdog, SCANNER_WATCHDOG_INTERVAL
self.hass,
self._async_scanner_watchdog,
SCANNER_WATCHDOG_INTERVAL,
f"{self.name} Bluetooth scanner watchdog",
)
@hass_callback
@ -224,7 +227,10 @@ class BaseHaRemoteScanner(BaseHaScanner):
self._async_expire_devices(dt_util.utcnow())
cancel_track = async_track_time_interval(
self.hass, self._async_expire_devices, timedelta(seconds=30)
self.hass,
self._async_expire_devices,
timedelta(seconds=30),
f"{self.name} Bluetooth scanner device expire",
)
cancel_stop = self.hass.bus.async_listen(
EVENT_HOMEASSISTANT_STOP, self._async_save_history

View file

@ -276,6 +276,7 @@ class BluetoothManager:
self.hass,
self._async_check_unavailable,
timedelta(seconds=UNAVAILABLE_TRACK_SECONDS),
"Bluetooth manager unavailable tracking",
)
@hass_callback

View file

@ -174,7 +174,10 @@ class BondEntity(Entity):
self._bpup_subs.subscribe(self._device_id, self._async_bpup_callback)
self.async_on_remove(
async_track_time_interval(
self.hass, self._async_update_if_bpup_not_alive, _FALLBACK_SCAN_INTERVAL
self.hass,
self._async_update_if_bpup_not_alive,
_FALLBACK_SCAN_INTERVAL,
f"Bond {self.entity_id} fallback polling",
)
)

View file

@ -379,7 +379,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
entity.async_update_token()
entity.async_write_ha_state()
unsub = async_track_time_interval(hass, update_tokens, TOKEN_CHANGE_INTERVAL)
unsub = async_track_time_interval(
hass, update_tokens, TOKEN_CHANGE_INTERVAL, "Camera update tokens"
)
@callback
def unsub_track_time_interval(_event: Event) -> None:

View file

@ -423,7 +423,12 @@ def async_setup_scanner_platform(
hass.async_create_task(async_see_device(**kwargs))
async_track_time_interval(hass, async_device_tracker_scan, interval)
async_track_time_interval(
hass,
async_device_tracker_scan,
interval,
f"device_tracker {platform} legacy scan",
)
hass.async_create_task(async_device_tracker_scan(None))

View file

@ -260,7 +260,7 @@ class NetworkWatcher(WatcherBase):
"""Start scanning for new devices on the network."""
self._discover_hosts = DiscoverHosts()
self._unsub = async_track_time_interval(
self.hass, self.async_start_discover, SCAN_INTERVAL
self.hass, self.async_start_discover, SCAN_INTERVAL, "DHCP network watcher"
)
self.async_start_discover()

View file

@ -272,6 +272,7 @@ class HKDevice:
self.hass,
self.async_update_available_state,
timedelta(seconds=BLE_AVAILABILITY_CHECK_INTERVAL),
f"HomeKit Controller {self.unique_id} BLE availability check poll",
)
)
# BLE devices always get an RSSI sensor as well
@ -286,7 +287,10 @@ class HKDevice:
# in the log about concurrent polling.
self.config_entry.async_on_unload(
async_track_time_interval(
self.hass, self.async_request_update, self.pairing.poll_interval
self.hass,
self.async_request_update,
self.pairing.poll_interval,
f"HomeKit Controller {self.unique_id} availability check poll",
)
)

View file

@ -296,7 +296,10 @@ class Recorder(threading.Thread):
run_immediately=True,
)
self._queue_watcher = async_track_time_interval(
self.hass, self._async_check_queue, timedelta(minutes=10)
self.hass,
self._async_check_queue,
timedelta(minutes=10),
"Recorder queue watcher",
)
@callback
@ -596,13 +599,19 @@ class Recorder(threading.Thread):
# to prevent errors from unexpected disconnects
if self.dialect_name != SupportedDialect.SQLITE:
self._keep_alive_listener = async_track_time_interval(
self.hass, self._async_keep_alive, timedelta(seconds=KEEPALIVE_TIME)
self.hass,
self._async_keep_alive,
timedelta(seconds=KEEPALIVE_TIME),
"Recorder keep alive",
)
# If the commit interval is not 0, we need to commit periodically
if self.commit_interval:
self._commit_listener = async_track_time_interval(
self.hass, self._async_commit, timedelta(seconds=self.commit_interval)
self.hass,
self._async_commit,
timedelta(seconds=self.commit_interval),
"Recorder commit",
)
# Run nightly tasks at 4:12am

View file

@ -401,7 +401,7 @@ class Scanner:
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop)
self._cancel_scan = async_track_time_interval(
self.hass, self.async_scan, SCAN_INTERVAL
self.hass, self.async_scan, SCAN_INTERVAL, "SSDP scanner"
)
# Trigger the initial-scan.

View file

@ -479,6 +479,7 @@ class EntityPlatform:
self.hass,
self._update_entity_states,
self.scan_interval,
f"EntityPlatform poll {self.domain}.{self.platform_name}",
)
def _entity_id_already_exists(self, entity_id: str) -> tuple[bool, bool]:

View file

@ -1397,6 +1397,7 @@ def async_track_time_interval(
hass: HomeAssistant,
action: Callable[[datetime], Coroutine[Any, Any, None] | None],
interval: timedelta,
name: str | None = None,
) -> CALLBACK_TYPE:
"""Add a listener that fires repetitively at every timedelta interval."""
remove: CALLBACK_TYPE
@ -1419,9 +1420,12 @@ def async_track_time_interval(
)
hass.async_run_hass_job(job, now)
interval_listener_job = HassJob(
interval_listener, f"track time interval listener {interval}"
)
if name:
job_name = f"{name}: track time interval {interval}"
else:
job_name = f"track time interval {interval}"
interval_listener_job = HassJob(interval_listener, job_name)
remove = async_track_point_in_utc_time(hass, interval_listener_job, next_interval())
def remove_listener() -> None:

View file

@ -216,7 +216,10 @@ class RestoreStateData:
# Dump states periodically
cancel_interval = async_track_time_interval(
self.hass, _async_dump_states, STATE_DUMP_INTERVAL
self.hass,
_async_dump_states,
STATE_DUMP_INTERVAL,
"RestoreStateData dump states",
)
async def _async_dump_states_at_stop(*_: Any) -> None:

View file

@ -3438,6 +3438,28 @@ async def test_track_time_interval(hass: HomeAssistant) -> None:
assert len(specific_runs) == 2
async def test_track_time_interval_name(hass: HomeAssistant) -> None:
"""Test tracking time interval name.
This test is to ensure that when a name is passed to async_track_time_interval,
that the name can be found in the TimerHandle when stringified.
"""
specific_runs = []
unique_string = "xZ13"
unsub = async_track_time_interval(
hass,
callback(lambda x: specific_runs.append(x)),
timedelta(seconds=10),
unique_string,
)
scheduled = getattr(hass.loop, "_scheduled")
assert any(handle for handle in scheduled if unique_string in str(handle))
unsub()
assert all(handle for handle in scheduled if unique_string not in str(handle))
await hass.async_block_till_done()
async def test_track_sunrise(hass: HomeAssistant) -> None:
"""Test track the sunrise."""
latitude = 32.87336