Serialise time zone adoption with the missed-sweep scheduler
The wake flag compared an adoption only against the plan the loop last
recorded, so New York -> UTC -> New York during the re-plan read left
the scheduler sleeping on UTC midnight; and an adoption committing
between the pre-sweep check and the sweep still let the stale sweep run.
`MissedSweepScheduler.settings_lock` now serialises the panel's adoption
(write plus `settings_changed`) with the loop's plan read and with its
pre-sweep re-read plus sweep. It is never held across the wait, and the
loop holds nothing else while acquiring it, so a panel request is at
most delayed by one settings read or one sweep.
`_sleep_unless_woken` now cancels and awaits both child tasks, and
re-raises a failed sleep inside the loop's retry block, so the backoff
runs instead of a sweep and nothing outlives `stop()`.
Tests (all four fail on bcf387d): the successive-zone race, an adoption
issued during the pre-sweep check, a failing sleep, and stop() waiting
for the sleep's cancellation cleanup.
Task: 6351b36d-0eef-4e7d-bf5a-96b754cbc883
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+9
-5
@@ -200,17 +200,21 @@ async def _household_clock(
|
||||
(:func:`nestquest_core.settings_store.adopt_reported_timezone`), so
|
||||
the admin plane follows it too, and the already-sleeping missed-sweep
|
||||
scheduler is told (:meth:`MissedSweepScheduler.settings_changed`) so
|
||||
it re-plans for the household rollover. An invalid
|
||||
it re-plans for the household rollover — under the scheduler's
|
||||
``settings_lock``, so the adoption never lands between its settings
|
||||
check and its sweep. An invalid
|
||||
reported zone is logged and ignored — the panel keeps serving on
|
||||
the stored settings.
|
||||
"""
|
||||
reported = request.headers.get(PANEL_TIMEZONE_HEADER, "").strip()
|
||||
if reported:
|
||||
scheduler = request.app.state.sweep_scheduler
|
||||
try:
|
||||
settings = await core_settings_store.adopt_reported_timezone(
|
||||
database, reported
|
||||
)
|
||||
request.app.state.sweep_scheduler.settings_changed(settings)
|
||||
async with scheduler.settings_lock:
|
||||
settings = await core_settings_store.adopt_reported_timezone(
|
||||
database, reported
|
||||
)
|
||||
scheduler.settings_changed(settings)
|
||||
except ValueError:
|
||||
LOGGER.warning(
|
||||
"Ignoring invalid %s header value %r",
|
||||
|
||||
Reference in New Issue
Block a user