Fix race condition where timer.start_time is None while is_running() is True (#1295)

When start() creates a task with asyncio.create_task(), the task is scheduled
but not immediately executed. This means is_running() returns True (task exists
and not done), but start_time is still None because _run() hasn't executed yet.

This causes a TypeError when comparing event.time_fired > timer.start_time.

Fix by setting start_time in start() before creating the task.

Fixes #1272
This commit is contained in:
Bas Nijholt 2025-11-27 09:27:13 -08:00 committed by GitHub
commit 6f846c26ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2680,7 +2680,6 @@ class _AsyncSingleShotTimer:
async def _run(self):
"""Run the timer. Don't call this directly, use start() instead."""
self.start_time = dt_util.utcnow()
await asyncio.sleep(self.delay)
if self.callback:
if asyncio.iscoroutinefunction(self.callback):
@ -2696,6 +2695,10 @@ class _AsyncSingleShotTimer:
"""Start the timer."""
if self.task is not None and not self.task.done():
self.task.cancel()
# Set start_time before creating task to avoid race condition
# where is_running() returns True but start_time is still None
# See: https://github.com/basnijholt/adaptive-lighting/issues/1272
self.start_time = dt_util.utcnow()
self.task = asyncio.create_task(self._run())
def cancel(self):