Skip to content

Commit 085fba0

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

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
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: 18 additions & 2 deletions
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
)
@@ -604,8 +606,13 @@ def reset(self, *, start_delay: timedelta = timedelta(0)) -> None:
604606

605607
if start_delay_ms < 0:
606608
raise ValueError(f"`start_delay` can't be negative, got {start_delay}")
607-
self._stopped = False
609+
608610
self._next_tick_time = self._now() + start_delay_ms + self._interval
611+
612+
if self.is_running:
613+
self._reset_event.set()
614+
615+
self._stopped = False
609616
self._current_drift = None
610617

611618
def stop(self) -> None:
@@ -621,6 +628,7 @@ def stop(self) -> None:
621628
self._stopped = True
622629
# We need to make sure it's not None, otherwise `ready()` will start it
623630
self._next_tick_time = self._now()
631+
self._reset_event.set()
624632

625633
# We need a noqa here because the docs have a Raises section but the documented
626634
# exceptions are raised indirectly.
@@ -664,7 +672,15 @@ async def ready(self) -> bool: # noqa: DOC502
664672
# could be reset while we are sleeping, in which case we need to recalculate
665673
# the time to the next tick and try again.
666674
while time_to_next_tick > 0:
667-
await asyncio.sleep(time_to_next_tick / 1_000_000)
675+
await next(
676+
asyncio.as_completed(
677+
[
678+
asyncio.sleep(time_to_next_tick / 1_000_000),
679+
self._reset_event.wait(),
680+
]
681+
)
682+
)
683+
self._reset_event.clear()
668684
now = self._now()
669685
time_to_next_tick = self._next_tick_time - now
670686

0 commit comments

Comments
 (0)