From ecd11b818cf338db9244aad165427fbc4bfe240c Mon Sep 17 00:00:00 2001 From: Daniel Zullo Date: Tue, 1 Oct 2024 09:57:57 +0200 Subject: [PATCH 1/2] Add polling parameters to ConfigManagingActor The ConfigManagingActor now allows to force file polling and set the polling interval. Signed-off-by: Daniel Zullo --- RELEASE_NOTES.md | 4 +++- pyproject.toml | 2 +- src/frequenz/sdk/config/_config_managing.py | 14 +++++++++++++- tests/actor/test_config_manager.py | 8 ++++++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 61ee6f2ad..1b7bfb787 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,7 +10,9 @@ ## New Features - +- `ConfigManagingActor`: The file polling mechanism is now forced by default. Two new parameters have been added: + - `force_polling`: Whether to force file polling to check for changes. Default is `True`. + - `polling_interval`: The interval to check for changes. Only relevant if polling is enabled. Default is 1 second. ## Bug Fixes diff --git a/pyproject.toml b/pyproject.toml index 23a5465c5..09fc14aec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ # changing the version # (plugins.mkdocstrings.handlers.python.import) "frequenz-client-microgrid >= 0.5.1, < 0.6.0", - "frequenz-channels >= 1.1.0, < 2.0.0", + "frequenz-channels >= 1.2.0, < 2.0.0", "networkx >= 2.8, < 4", "numpy >= 1.26.4, < 2", "typing_extensions >= 4.6.1, < 5", diff --git a/src/frequenz/sdk/config/_config_managing.py b/src/frequenz/sdk/config/_config_managing.py index d1bdd13f4..8d97fcef4 100644 --- a/src/frequenz/sdk/config/_config_managing.py +++ b/src/frequenz/sdk/config/_config_managing.py @@ -7,6 +7,7 @@ import pathlib import tomllib from collections import abc +from datetime import timedelta from typing import Any, assert_never from frequenz.channels import Sender @@ -29,6 +30,7 @@ class ConfigManagingActor(Actor): reading too. """ + # pylint: disable-next=too-many-arguments def __init__( self, config_path: pathlib.Path | str, @@ -36,6 +38,8 @@ def __init__( event_types: abc.Set[EventType] = frozenset(EventType), *, name: str | None = None, + force_polling: bool = True, + polling_interval: timedelta = timedelta(seconds=1), ) -> None: """Initialize this instance. @@ -45,6 +49,9 @@ def __init__( event_types: The set of event types to monitor. name: The name of the actor. If `None`, `str(id(self))` will be used. This is used mostly for debugging purposes. + force_polling: Whether to force file polling to check for changes. + polling_interval: The interval to poll for changes. Only relevant if + polling is enabled. """ super().__init__(name=name) self._config_path: pathlib.Path = ( @@ -54,6 +61,8 @@ def __init__( ) self._output: Sender[abc.Mapping[str, Any]] = output self._event_types: abc.Set[EventType] = event_types + self._force_polling: bool = force_polling + self._polling_interval: timedelta = polling_interval def _read_config(self) -> abc.Mapping[str, Any]: """Read the contents of the configuration file. @@ -89,7 +98,10 @@ async def _run(self) -> None: # parent directory instead just in case a configuration file doesn't exist yet # or it is deleted and recreated again. file_watcher = FileWatcher( - paths=[self._config_path.parent], event_types=self._event_types + paths=[self._config_path.parent], + event_types=self._event_types, + force_polling=self._force_polling, + polling_interval=self._polling_interval, ) try: diff --git a/tests/actor/test_config_manager.py b/tests/actor/test_config_manager.py index baa82a39e..542081b78 100644 --- a/tests/actor/test_config_manager.py +++ b/tests/actor/test_config_manager.py @@ -71,7 +71,9 @@ async def test_update(self, config_file: pathlib.Path) -> None: ) config_receiver = config_channel.new_receiver() - async with ConfigManagingActor(config_file, config_channel.new_sender()): + async with ConfigManagingActor( + config_file, config_channel.new_sender(), force_polling=False + ): config = await config_receiver.receive() assert config is not None assert config.get("logging_lvl") == "DEBUG" @@ -100,7 +102,9 @@ async def test_update_relative_path(self, config_file: pathlib.Path) -> None: current_dir = pathlib.Path.cwd() relative_path = os.path.relpath(config_file, current_dir) - async with ConfigManagingActor(relative_path, config_channel.new_sender()): + async with ConfigManagingActor( + relative_path, config_channel.new_sender(), force_polling=False + ): config = await config_receiver.receive() assert config is not None assert config.get("var2") is None From 0c0563fddf037a6dcfe1b09eb1ef982330fff485 Mon Sep 17 00:00:00 2001 From: Sahas Subramanian Date: Sun, 6 Oct 2024 12:43:48 +0200 Subject: [PATCH 2/2] Reduce wait time in battery_pool test This test was failing in arm64 runs, because of a large time difference. This fixes the issue. Signed-off-by: Sahas Subramanian --- tests/timeseries/_battery_pool/test_battery_pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/timeseries/_battery_pool/test_battery_pool.py b/tests/timeseries/_battery_pool/test_battery_pool.py index 3274efabf..a3f58b6a9 100644 --- a/tests/timeseries/_battery_pool/test_battery_pool.py +++ b/tests/timeseries/_battery_pool/test_battery_pool.py @@ -1306,7 +1306,7 @@ async def run_power_bounds_test( # pylint: disable=too-many-locals # One inverter stopped sending data, use one remaining inverter await streamer.stop_streaming(next(iter(bat_invs_map[batteries_in_pool[0]]))) - await asyncio.sleep(MAX_BATTERY_DATA_AGE_SEC + 0.2) + await asyncio.sleep(MAX_BATTERY_DATA_AGE_SEC + 0.1) msg = await asyncio.wait_for(receiver.receive(), timeout=waiting_time_sec) compare_messages( msg,