Skip to content

Commit 5f11e00

Browse files
Change ConfigManagingActor: move creating FileWatcher to constructor
FileWatcher instance should be create in constructor instead of in _run() method. Otherwise, if the actor restarts, we will lost all events that happened while the actor was down. Signed-off-by: Elzbieta Kotulska <[email protected]>
1 parent 5ed98ee commit 5f11e00

File tree

1 file changed

+66
-48
lines changed

1 file changed

+66
-48
lines changed

src/frequenz/sdk/config/_config_managing.py

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,42 @@ def __init__(
106106
for config_path in config_paths
107107
]
108108
self._output: Sender[abc.Mapping[str, Any]] = output
109-
self._event_types: abc.Set[EventType] = event_types
110-
self._force_polling: bool = force_polling
111-
self._polling_interval: timedelta = polling_interval
109+
110+
# FileWatcher instance should be create here instead of in _run().
111+
# Otherwise, if the actor restarts, we will lost all the events that happened
112+
# while the actor was down.
113+
self._file_watcher = self._create_file_watcher(
114+
force_polling, polling_interval, event_types
115+
)
116+
117+
def _create_file_watcher(
118+
self,
119+
force_polling: bool,
120+
polling_interval: timedelta,
121+
event_types: abc.Set[EventType],
122+
) -> FileWatcher:
123+
"""Create a FileWatcher instance to monitor the configuration files.
124+
125+
Args:
126+
force_polling: Whether to force file polling to check for changes.
127+
polling_interval: The interval to poll for changes. Only relevant if
128+
polling is enabled.
129+
event_types: The set of event types to monitor.
130+
131+
Returns:
132+
A FileWatcher instance.
133+
"""
134+
parent_paths = {p.parent for p in self._config_paths}
135+
136+
# FileWatcher can't watch for non-existing files, so we need to watch for the
137+
# parent directories instead just in case a configuration file doesn't exist yet
138+
# or it is deleted and recreated again.
139+
return FileWatcher(
140+
paths=list(parent_paths),
141+
event_types=event_types,
142+
force_polling=force_polling,
143+
polling_interval=polling_interval,
144+
)
112145

113146
def _read_config(self) -> abc.Mapping[str, Any]:
114147
"""Read the contents of the configuration file.
@@ -156,51 +189,36 @@ async def _run(self) -> None:
156189
"""
157190
await self.send_config()
158191

159-
parent_paths = {p.parent for p in self._config_paths}
160-
161-
# FileWatcher can't watch for non-existing files, so we need to watch for the
162-
# parent directories instead just in case a configuration file doesn't exist yet
163-
# or it is deleted and recreated again.
164-
file_watcher = FileWatcher(
165-
paths=list(parent_paths),
166-
event_types=self._event_types,
167-
force_polling=self._force_polling,
168-
polling_interval=self._polling_interval,
169-
)
170-
171-
try:
172-
async for event in file_watcher:
173-
# Since we are watching the whole parent directories, we need to make
174-
# sure we only react to events related to the configuration files we
175-
# are interested in.
176-
if not any(event.path.samefile(p) for p in self._config_paths):
177-
continue
178-
179-
match event.type:
180-
case EventType.CREATE:
181-
_logger.info(
182-
"%s: The configuration file %s was created, sending new config...",
183-
self,
184-
event.path,
185-
)
186-
await self.send_config()
187-
case EventType.MODIFY:
188-
_logger.info(
189-
"%s: The configuration file %s was modified, sending update...",
190-
self,
191-
event.path,
192-
)
193-
await self.send_config()
194-
case EventType.DELETE:
195-
_logger.info(
196-
"%s: The configuration file %s was deleted, ignoring...",
197-
self,
198-
event.path,
199-
)
200-
case _:
201-
assert_never(event.type)
202-
finally:
203-
del file_watcher
192+
async for event in self._file_watcher:
193+
# Since we are watching the whole parent directories, we need to make
194+
# sure we only react to events related to the configuration files we
195+
# are interested in.
196+
if not any(event.path.samefile(p) for p in self._config_paths):
197+
continue
198+
199+
match event.type:
200+
case EventType.CREATE:
201+
_logger.info(
202+
"%s: The configuration file %s was created, sending new config...",
203+
self,
204+
event.path,
205+
)
206+
await self.send_config()
207+
case EventType.MODIFY:
208+
_logger.info(
209+
"%s: The configuration file %s was modified, sending update...",
210+
self,
211+
event.path,
212+
)
213+
await self.send_config()
214+
case EventType.DELETE:
215+
_logger.info(
216+
"%s: The configuration file %s was deleted, ignoring...",
217+
self,
218+
event.path,
219+
)
220+
case _:
221+
assert_never(event.type)
204222

205223

206224
def _recursive_update(

0 commit comments

Comments
 (0)