feat: hot-reload YAML config without restarting the daemon (refs #424)#481
Draft
Copilot wants to merge 6 commits into
Draft
feat: hot-reload YAML config without restarting the daemon (refs #424)#481Copilot wants to merge 6 commits into
Copilot wants to merge 6 commits into
Conversation
- Add ReadAndValidateConfig() to configuration package: reads a fresh viper instance, applies defaults/transformations/deprecations, and validates without touching the global CurrentConfig. - Refactor applyTransformations/applyDeprecations to accept *Configuration so they can be called on arbitrary instances, not just the global one. - Fix containsCmdFan/containsCmdSensors to use the passed-in config instead of the global CurrentConfig (was a latent bug in validateConfig). - Extract makeDecodeHookOptions() and setDefaultValuesOnViper() helpers to share decode/default logic between LoadConfig and ReadAndValidateConfig. - Add SetCurve(curves.SpeedCurve) to the FanController interface; implement it on DefaultFanController behind a sync.RWMutex so the running control loop and the hot-reload manager can race safely. - New internal/reload package: ReloadManager watches the config file with fsnotify (debounced 500 ms) and responds to SIGHUP. On a valid change it updates CurrentConfig, recreates all SpeedCurve objects (PID state is intentionally reset), and calls SetCurve on each fan controller. If validation fails the daemon keeps running with the previous config. - Wire ReloadManager into RunDaemon via the existing run.Group so it participates in clean shutdown. - Promote fsnotify from indirect to direct dependency in go.mod. - Add unit tests: internal/configuration/reload_test.go covers ReadAndValidateConfig (valid, invalid YAML, validation failure, no side effects on CurrentConfig); internal/reload/reload_test.go covers applyNewConfig, the full reload() pipeline (accept/reject paths), PID setpoint update end-to-end, and Run context-cancellation lifecycle." Agent-Logs-Url: https://github.com/markusressel/fan2go/sessions/af1e65c2-a288-48c7-b16e-ee100ddb49d4 Co-authored-by: markusressel <14024504+markusressel@users.noreply.github.com>
- backend.go: make reload manager interrupt func a no-op; context cancellation already drives clean shutdown via rm.Run(ctx). - reload.go: pass ctx to reload() so the apply step is skipped when the daemon is shutting down (check ctx.Done() before applyNewConfig). - reload_test.go: add require.NoError for NewSpeedCurve in test setup; use type-asserted SetValue() instead of direct struct-field access to avoid bypassing the value mutex. Agent-Logs-Url: https://github.com/markusressel/fan2go/sessions/af1e65c2-a288-48c7-b16e-ee100ddb49d4 Co-authored-by: markusressel <14024504+markusressel@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Implement hot reloading for YAML configuration file in fan2go
feat: hot-reload YAML config without restarting the daemon (refs #424)
May 23, 2026
…ontrol algorithm) Agent-Logs-Url: https://github.com/markusressel/fan2go/sessions/93f76bb2-2ae1-4066-a167-6872468e0a93 Co-authored-by: markusressel <14024504+markusressel@users.noreply.github.com>
…ated field access Agent-Logs-Url: https://github.com/markusressel/fan2go/sessions/93f76bb2-2ae1-4066-a167-6872468e0a93 Co-authored-by: markusressel <14024504+markusressel@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
internal/monitor.go: makeTempSensorPollingRatedynamic — remove storedpollingRatefield, reset ticker when config changesinternal/backend.go: updateNewSensorMonitorcall (droppollingRatearg)internal/controller/controller.go: addSetControlLooptoFanControllerinterface + impl; protectcontrolLoopwithcontrolLoopMu; makeRpmPollingRateandAdjustmentTickRatetickers dynamic (reset on change)internal/reload/reload.go: propagate per-fan config changes to fan objects on reload; rebuild and push control loop viaSetControlLoop; addbuildControlLoopForFanhelperinternal/reload/reload_test.go: addSetControlLoopstub + stored config tofakeController/fakeFan; add 3 new tests for control loop update, algorithm change, and per-fan config propagation//nolint:staticcheckinstead of//nolint:all