mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-11 09:12:48 +03:00
re-apply runtime overrides to the config without re-broadcasting them (#23739)
/api/config/set and camera deletion re-parse yaml into a fresh FrigateConfig and swap it in, then re-layered the persisted runtime toggle overrides so a camera the user turned off wouldn't come back on. That re-layer ran apply_runtime_state, which replays each override through the command handlers, so every save re-published a ZMQ config update, a retained MQTT state message, and a runtime-state disk write for every camera with a stored toggle. All of it was redundant: the worker processes were never swapped and still hold the live toggle values, so only the in-process config object the API and dispatcher read was out of date. The extra traffic churned the retained MQTT topics, amplified disk writes, and co-drained enabled updates with other topics on the config socket. Add Dispatcher.reapply_runtime_state_to_config, which corrects only the swapped-in config object, mirroring the field mutations and gates of the _on_*_command handlers with no ZMQ, MQTT, or disk writes. swap_runtime_config now calls it instead of apply_runtime_state; apply_runtime_state is unchanged and still used at startup, where the workers genuinely must be told.
This commit is contained in:
@@ -492,6 +492,48 @@ class Dispatcher:
|
||||
"""
|
||||
self._runtime_state.clear_camera(camera)
|
||||
|
||||
def reapply_runtime_state_to_config(self) -> None:
|
||||
"""Re-apply persisted runtime overrides to the swapped-in config object.
|
||||
|
||||
After config/set (or a camera delete) parses fresh yaml and swaps the
|
||||
config, the worker processes still hold the live toggle values and the
|
||||
overrides are already on disk, so only the in-process config object is
|
||||
out of date. Unlike apply_runtime_state (used at startup, where workers
|
||||
must be told), this makes no ZMQ, MQTT, or disk writes, it just corrects
|
||||
the config the API and dispatcher read.
|
||||
|
||||
The field mutations and gates mirror the _on_*_command handlers; keep
|
||||
the two in sync if a tracked toggle is added or its gate changes.
|
||||
"""
|
||||
state = self._runtime_state.load()
|
||||
|
||||
for camera_name, features in state.items():
|
||||
camera = self.config.cameras.get(camera_name)
|
||||
|
||||
if camera is None:
|
||||
continue
|
||||
|
||||
for topic, value in features.items():
|
||||
if topic == "enabled":
|
||||
if value and not camera.enabled_in_config:
|
||||
continue
|
||||
camera.enabled = value
|
||||
elif topic == "detect":
|
||||
camera.detect.enabled = value
|
||||
# detection requires motion, mirror the handler coupling
|
||||
if value and not camera.motion.enabled:
|
||||
camera.motion.enabled = True
|
||||
elif topic == "snapshots":
|
||||
camera.snapshots.enabled = value
|
||||
elif topic == "recordings":
|
||||
if value and not camera.record.enabled_in_config:
|
||||
continue
|
||||
camera.record.enabled = value
|
||||
elif topic == "audio":
|
||||
if value and not camera.audio.enabled_in_config:
|
||||
continue
|
||||
camera.audio.enabled = value
|
||||
|
||||
def _on_detect_command(self, camera_name: str, payload: str) -> None:
|
||||
"""Callback for detect topic."""
|
||||
detect_settings = self.config.cameras[camera_name].detect
|
||||
|
||||
Reference in New Issue
Block a user