From 08662b9f2a2f7ad57ab7d337ccd8b676177e9988 Mon Sep 17 00:00:00 2001 From: Sahas Subramanian Date: Mon, 16 Feb 2026 15:03:20 +0100 Subject: [PATCH 1/4] Close receiver when stopping `LatestValueCache` Signed-off-by: Sahas Subramanian --- src/frequenz/channels/_latest_value_cache.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frequenz/channels/_latest_value_cache.py b/src/frequenz/channels/_latest_value_cache.py index a9af9436..734a7024 100644 --- a/src/frequenz/channels/_latest_value_cache.py +++ b/src/frequenz/channels/_latest_value_cache.py @@ -53,6 +53,9 @@ class LatestValueCache(typing.Generic[T_co]): It provides a way to look up the latest value in a stream without any delay, as long as there has been one value received. + + Takes ownership of the receiver. When the cache is stopped, the receiver + will be closed. """ def __init__( @@ -108,7 +111,8 @@ async def _run(self) -> None: self._latest_value = value async def stop(self) -> None: - """Stop the cache.""" + """Stop the cache and close the owned receiver.""" + self._receiver.close() if not self._task.done(): self._task.cancel() try: From 2dd69a0a9fc841e13475be5b38b52499f1c06aff Mon Sep 17 00:00:00 2001 From: Sahas Subramanian Date: Mon, 16 Feb 2026 16:40:16 +0100 Subject: [PATCH 2/4] Annotate `LatestValueCache` members with type-hints Signed-off-by: Sahas Subramanian --- src/frequenz/channels/_latest_value_cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frequenz/channels/_latest_value_cache.py b/src/frequenz/channels/_latest_value_cache.py index 734a7024..83dcd2a5 100644 --- a/src/frequenz/channels/_latest_value_cache.py +++ b/src/frequenz/channels/_latest_value_cache.py @@ -69,10 +69,10 @@ def __init__( provided, a unique identifier will be generated from the object's [`id()`][id]. It is used mostly for debugging purposes. """ - self._receiver = receiver + self._receiver: Receiver[T_co] = receiver self._unique_id: str = hex(id(self)) if unique_id is None else unique_id self._latest_value: T_co | _Sentinel = _Sentinel() - self._task = asyncio.create_task( + self._task: asyncio.Task[None] = asyncio.create_task( self._run(), name=f"LatestValueCache«{self._unique_id}»" ) From cafd8d70203bf18da6294a4e23db92713a2ed4b6 Mon Sep 17 00:00:00 2001 From: Sahas Subramanian Date: Mon, 16 Feb 2026 17:01:00 +0100 Subject: [PATCH 3/4] Disallow fetching from stopped `LatestValueCache`s Signed-off-by: Sahas Subramanian --- src/frequenz/channels/_latest_value_cache.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/frequenz/channels/_latest_value_cache.py b/src/frequenz/channels/_latest_value_cache.py index 83dcd2a5..4a3dff87 100644 --- a/src/frequenz/channels/_latest_value_cache.py +++ b/src/frequenz/channels/_latest_value_cache.py @@ -75,6 +75,7 @@ def __init__( self._task: asyncio.Task[None] = asyncio.create_task( self._run(), name=f"LatestValueCache«{self._unique_id}»" ) + self._stopped: bool = False @property def unique_id(self) -> str: @@ -96,6 +97,8 @@ def get(self) -> T_co: """ if isinstance(self._latest_value, _Sentinel): raise ValueError("No value has been received yet.") + if self._stopped: + raise ValueError("Cache has been stopped.") return self._latest_value def has_value(self) -> bool: @@ -113,6 +116,7 @@ async def _run(self) -> None: async def stop(self) -> None: """Stop the cache and close the owned receiver.""" self._receiver.close() + self._stopped = True if not self._task.done(): self._task.cancel() try: From a812c29929f21fb7acb65f73b75181a7b1b8081d Mon Sep 17 00:00:00 2001 From: Sahas Subramanian Date: Mon, 16 Feb 2026 15:07:40 +0100 Subject: [PATCH 4/4] Update release notes Signed-off-by: Sahas Subramanian --- RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 96a0240b..7e1258ff 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,7 +6,8 @@ ## Upgrading - +- `LatestValueCache` now closes the receiver when it is stopped. +- Fetching values from stopped `LatestValueCache` instances is now disallowed. ## New Features