package config import ( "log/slog" "time" "github.com/fsnotify/fsnotify" ) // Watch watches the config file and calls onReload with the new config on change. // Debounces Write/Create events by 500ms to avoid multiple triggers on a single save. func Watch(path string, provider *Provider, onReload func(*Config)) error { watcher, err := fsnotify.NewWatcher() if err != nil { return err } if err := watcher.Add(path); err != nil { watcher.Close() return err } go func() { defer watcher.Close() var debounce *time.Timer for { select { case event, ok := <-watcher.Events: if !ok { return } if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) { if debounce != nil { debounce.Stop() } debounce = time.AfterFunc(500*time.Millisecond, func() { cfg, err := Load(path) if err != nil { slog.Error("hot reload: invalid config, keeping old", "err", err) return } provider.Swap(cfg) slog.Info("config reloaded") if onReload != nil { onReload(cfg) } }) } case err, ok := <-watcher.Errors: if !ok { return } slog.Error("config watcher error", "err", err) } } }() return nil }