Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add polling parameters to ConfigManagingActor #1082

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -10,7 +10,9 @@

## New Features

<!-- Here goes the main new features and examples or instructions on how to use them -->
- `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

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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",
14 changes: 13 additions & 1 deletion src/frequenz/sdk/config/_config_managing.py
Original file line number Diff line number Diff line change
@@ -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,13 +30,16 @@ class ConfigManagingActor(Actor):
reading too.
"""

# pylint: disable-next=too-many-arguments
def __init__(
self,
config_path: pathlib.Path | str,
output: Sender[abc.Mapping[str, Any]],
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:
8 changes: 6 additions & 2 deletions tests/actor/test_config_manager.py
Original file line number Diff line number Diff line change
@@ -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
Loading