Skip to content

Latest commit

 

History

History
95 lines (74 loc) · 2.93 KB

File metadata and controls

95 lines (74 loc) · 2.93 KB

Bug Fix Summary

Bug 1: Watcher Errors Silently Discarded

Problem

In loader/watcher.go, file watcher errors were being silently discarded with _ = err, making debugging difficult in production.

Solution

  • Added onError func(error) field to the Watcher struct
  • Updated NewWatcher() signature to accept an optional error handler as the third parameter
  • When a watcher error occurs:
    • If onError is set, it calls the handler
    • If onError is nil, it prints to stderr (not stdout)

Changes

  • loader/watcher.go:
    • Added onError field to Watcher struct
    • Modified NewWatcher(paths []string, callback func(), onError func(error)) signature
    • Updated error handling in watch() method to call handler or print to stderr

Bug 2: Hot-Reload Failures Silent in Production

Problem

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.

Solution

  • Added onReloadError func(error) field to the Loader struct
  • Added OnReloadError(func(error)) *Loader chainable method (same pattern as OnReload)
  • When hot-reload fails:
    • Old config is preserved (not overwritten)
    • If onReloadError is set, it calls the handler
    • If onReloadError is nil, it prints to stderr
  • Updated NewWatcher call to pass through the error handler

Changes

  • loader/loader.go:
    • Added onReloadError func(error) field to Loader struct
    • Added OnReloadError(callback func(error)) *Loader method
    • 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 NewWatcher for watcher-level errors

Testing

New Test Case

Added TestHotReloadErrorPreservesOldConfig in loader/loader_test.go:

  • Loads valid config initially
  • Writes invalid YAML to trigger reload error
  • Verifies old config is preserved
  • Verifies OnReloadError callback is invoked

Test Results

All tests pass:

=== RUN   TestHotReloadErrorPreservesOldConfig
--- PASS: TestHotReloadErrorPreservesOldConfig (0.50s)

API Compatibility

✅ No breaking changes to public API:

  • Load(), WithYAML(), WithJSON(), WithEnv(), WithHotReload() remain unchanged
  • OnReloadError() is a new optional chainable method
  • Existing code continues to work without modification

Usage Example

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.