55
66import asyncio
77from datetime import datetime , timedelta , timezone
8+ from typing import Optional
89
910from frequenz .channels .base_classes import Receiver
1011
@@ -61,6 +62,7 @@ def __init__(self, interval: float) -> None:
6162 self ._stopped = False
6263 self ._interval = timedelta (seconds = interval )
6364 self ._next_msg_time = datetime .now (timezone .utc ) + self ._interval
65+ self ._now : Optional [datetime ] = None
6466
6567 def reset (self ) -> None :
6668 """Reset the timer to start timing from `now`."""
@@ -75,11 +77,12 @@ def stop(self) -> None:
7577 """
7678 self ._stopped = True
7779
78- async def __anext__ (self ) -> datetime :
80+ async def _ready (self ) -> None :
7981 """Return the current time (in UTC) once the next tick is due.
8082
8183 Raises:
82- StopAsyncIteration: When the channel is closed.
84+ StopAsyncIteration: if [stop()][frequenz.channels.Timer.stop] has been
85+ called on the timer.
8386
8487 Returns:
8588 The time of the next tick in UTC or `None` if
@@ -90,6 +93,10 @@ async def __anext__(self) -> datetime:
9093 * **v0.11.0:** Returns a timezone-aware datetime with UTC timezone
9194 instead of a native datetime object.
9295 """
96+ # if there are messages waiting to be consumed, return immediately.
97+ if self ._now is not None :
98+ return
99+
93100 if self ._stopped :
94101 raise StopAsyncIteration ()
95102 now = datetime .now (timezone .utc )
@@ -98,7 +105,21 @@ async def __anext__(self) -> datetime:
98105 await asyncio .sleep (diff .total_seconds ())
99106 now = datetime .now (timezone .utc )
100107 diff = self ._next_msg_time - now
108+ self ._now = now
109+
110+ self ._next_msg_time = self ._now + self ._interval
111+
112+ def _get (self ) -> datetime :
113+ """Return the latest value once `_ready` is complete.
101114
102- self ._next_msg_time = now + self ._interval
115+ Raises:
116+ EOFError: When called before a call to `_ready()` finishes.
103117
118+ Returns:
119+ The timestamp for the next tick.
120+ """
121+ if self ._now is None :
122+ raise EOFError ("_get called before _ready finished" )
123+ now = self ._now
124+ self ._now = None
104125 return now
0 commit comments