Skip to content

Commit ef4ba90

Browse files
committed
Timer: Make stop() and reset() interrupt a waiting timer
Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent 62c2248 commit ef4ba90

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
## Bug Fixes
44

55
- `FileWatcher`: Fixed `ready()` method to return False when an error occurs. Before this fix, `select()` (and other code using `ready()`) never detected the `FileWatcher` was stopped and the `select()` loop was continuously waking up to inform the receiver was ready.
6+
7+
- `Timer.stop()` and `Timer.reset()` now immediately stop the timer if it is running. Before this fix, the timer would continue to run until the next interval.

src/frequenz/channels/timer.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ def __init__( # pylint: disable=too-many-arguments
523523
See the documentation of `MissedTickPolicy` for details.
524524
"""
525525

526+
self._reset_event = asyncio.Event()
527+
526528
self._loop: asyncio.AbstractEventLoop = (
527529
loop if loop is not None else asyncio.get_running_loop()
528530
)
@@ -605,7 +607,13 @@ def reset(self, *, start_delay: timedelta = timedelta(0)) -> None:
605607
if start_delay_ms < 0:
606608
raise ValueError(f"`start_delay` can't be negative, got {start_delay}")
607609
self._stopped = False
610+
611+
prev_next_tick_time = self._next_tick_time
608612
self._next_tick_time = self._now() + start_delay_ms + self._interval
613+
614+
if prev_next_tick_time and prev_next_tick_time > self._next_tick_time:
615+
self._reset_event.set()
616+
609617
self._current_drift = None
610618

611619
def stop(self) -> None:
@@ -621,6 +629,7 @@ def stop(self) -> None:
621629
self._stopped = True
622630
# We need to make sure it's not None, otherwise `ready()` will start it
623631
self._next_tick_time = self._now()
632+
self._reset_event.set()
624633

625634
# We need a noqa here because the docs have a Raises section but the documented
626635
# exceptions are raised indirectly.
@@ -664,7 +673,12 @@ async def ready(self) -> bool: # noqa: DOC502
664673
# could be reset while we are sleeping, in which case we need to recalculate
665674
# the time to the next tick and try again.
666675
while time_to_next_tick > 0:
667-
await asyncio.sleep(time_to_next_tick / 1_000_000)
676+
for fin in asyncio.as_completed(
677+
[asyncio.sleep(time_to_next_tick / 1_000_000), self._reset_event.wait()]
678+
):
679+
await fin
680+
break
681+
self._reset_event.clear()
668682
now = self._now()
669683
time_to_next_tick = self._next_tick_time - now
670684

0 commit comments

Comments
 (0)