In loader/watcher.go, file watcher errors were being silently discarded with _ = err, making debugging difficult in production.
- Added
onError func(error)field to theWatcherstruct - Updated
NewWatcher()signature to accept an optional error handler as the third parameter - When a watcher error occurs:
- If
onErroris set, it calls the handler - If
onErroris nil, it prints to stderr (not stdout)
- If
loader/watcher.go:- Added
onErrorfield toWatcherstruct - Modified
NewWatcher(paths []string, callback func(), onError func(error))signature - Updated error handling in
watch()method to call handler or print to stderr
- Added
In loader/loader.go, hot-reload failures were only printed to stdout with fmt.Printf(), which could be missed in production environments. Additionally, failed reloads would corrupt the config.
- Added
onReloadError func(error)field to theLoaderstruct - Added
OnReloadError(func(error)) *Loaderchainable method (same pattern asOnReload) - When hot-reload fails:
- Old config is preserved (not overwritten)
- If
onReloadErroris set, it calls the handler - If
onReloadErroris nil, it prints to stderr
- Updated
NewWatchercall to pass through the error handler
loader/loader.go:- Added
onReloadError func(error)field toLoaderstruct - Added
OnReloadError(callback func(error)) *Loadermethod - Updated hot-reload logic to:
- Create a backup of the old config before reloading
- Restore old config if reload fails
- Call error handler or print to stderr
- Pass error handler to
NewWatcherfor watcher-level errors
- Added
Added TestHotReloadErrorPreservesOldConfig in loader/loader_test.go:
- Loads valid config initially
- Writes invalid YAML to trigger reload error
- Verifies old config is preserved
- Verifies
OnReloadErrorcallback is invoked
All tests pass:
=== RUN TestHotReloadErrorPreservesOldConfig
--- PASS: TestHotReloadErrorPreservesOldConfig (0.50s)
✅ No breaking changes to public API:
Load(),WithYAML(),WithJSON(),WithEnv(),WithHotReload()remain unchangedOnReloadError()is a new optional chainable method- Existing code continues to work without modification
loader := config.New().
WithYAML("config.yaml").
WithHotReload().
OnReload(func(cfg interface{}) {
fmt.Println("Config reloaded successfully!")
}).
OnReloadError(func(err error) {
log.Printf("Failed to reload config: %v", err)
// Send alert, increment metric, etc.
})
if err := loader.Load(&cfg); err != nil {
log.Fatal(err)
}If OnReloadError is not set, errors are printed to stderr as a fallback.