Skip to content

Commit 73e647e

Browse files
committed
WIP: Add full example in the config module.
1 parent 44b3b5c commit 73e647e

File tree

1 file changed

+101
-1
lines changed

1 file changed

+101
-1
lines changed

src/frequenz/sdk/config/__init__.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,107 @@
11
# License: MIT
22
# Copyright © 2024 Frequenz Energy-as-a-Service GmbH
33

4-
"""Configuration management."""
4+
"""Configuration management.
5+
6+
Example: App configuring the global config manager.
7+
```python
8+
import asyncio
9+
import dataclasses
10+
import logging
11+
import sys
12+
13+
from collections.abc import Sequence
14+
from typing import assert_never
15+
16+
import marshmallow
17+
18+
from frequenz.channels import select, selected_from
19+
from frequenz.sdk.actor import Actor
20+
from frequenz.sdk.config import (
21+
ConfigManager,
22+
LoggingConfigUpdatingActor,
23+
wait_for_first
24+
)
25+
26+
_logger = logging.getLogger(__name__)
27+
28+
@dataclasses.dataclass
29+
class ActorConfig:
30+
name: str
31+
32+
class MyActor(Actor):
33+
def __init__(self, config_manager: ConfigManager, config_key: str | Sequence[str]) -> None:
34+
super().__init__()
35+
self._config_receiver = config_manager().new_receiver(config_key, ActorConfig)
36+
self._receiver = ...
37+
38+
async def _run(self) -> None:
39+
self._reconfigure(await wait_for_first(self._config_receiver))
40+
41+
async for selected in select(self._receiver, self._config_receiver):
42+
if selected_from(selected, self._receiver):
43+
...
44+
elif selected_from(selected, self._config_receiver):
45+
self._reconfigure(selected.value)
46+
47+
def _reconfigure(self, config_update: ActorConfig | Exception | None) -> None:
48+
match config_update:
49+
case ActorConfig():
50+
_logger.info(
51+
"New configuration received, updating actor settings."
52+
)
53+
# ...
54+
case None:
55+
_logger.info(
56+
"Configuration was unset, resetting to the default configuration."
57+
)
58+
# ...
59+
case Exception():
60+
_logger.info(
61+
"New configuration has errors, keeping the old configuration."
62+
)
63+
case unexpected:
64+
assert_never(unexpected)
65+
66+
67+
@dataclasses.dataclass
68+
class AppConfig:
69+
positive_int: int = dataclasses.field(
70+
default=42,
71+
metadata={"validate": marshmallow.validate.Range(min=0)},
72+
)
73+
74+
async def main() -> None:
75+
async with ConfigManager(["config.toml"]) as config_manager:
76+
receiver = config_manager.new_receiver("app", AppConfig)
77+
try:
78+
initial_config = await wait_for_first(receiver)
79+
except asyncio.TimeoutError:
80+
print("No configuration received in time")
81+
sys.exit(1)
82+
83+
_logger.info("App initialized with %s", initial_config.positive_int)
84+
actor = MyActor(config_manager, "actor")
85+
actor.start()
86+
87+
# Keep listening for new configurations updates
88+
async for config_update in receiver:
89+
...
90+
```
91+
92+
Example config:
93+
94+
```toml
95+
[app]
96+
positive_int = 42
97+
98+
[actor]
99+
name = "my_actor"
100+
101+
[logging.root_logger]
102+
level = "DEBUG"
103+
```
104+
"""
5105

6106
from ._logging_actor import LoggerConfig, LoggingConfig, LoggingConfigUpdatingActor
7107
from ._manager import ConfigManager, InvalidValueForKeyError, wait_for_first

0 commit comments

Comments
 (0)