🐛 fix(config): remove racy log.Info in WatchAndApply cancel goroutine
The cancel-handler goroutine emitted a "watcher stopped" log AFTER setting the watcherStopped flag. Because viper's internal watcher goroutine (started by viper.WatchConfig) has no public Stop and can outlive the context, this log call would race with subsequent zerolog.SetGlobalLevel from the next test's LoadConfig → SetupLogging. Symptom (under go test -race ./pkg/config/...): WARNING: DATA RACE Write at zerolog.SetGlobalLevel Previous read by zerolog.(*Logger).disabled in log.Info(...) Fix: drop the informational log. The flag is sufficient — the cancel ack does not need to be observable. Test cleanups (defer cancel()) already serialize via the t.Cleanup teardown order. Verified: go test -race ./pkg/config/... passes, full BDD suite green.
This commit is contained in:
@@ -730,11 +730,14 @@ func (c *Config) WatchAndApply(ctx context.Context) {
|
||||
// Stop the watcher on context cancel — we set a flag that the
|
||||
// OnConfigChange handler checks, avoiding the race with viper's
|
||||
// internal state that would occur if we called OnConfigChange again.
|
||||
// We deliberately do NOT log here: viper's internal watcher goroutine
|
||||
// has no public Stop, so it can outlive ctx, and a zerolog call here
|
||||
// would race with the next test's LoadConfig → SetupLogging →
|
||||
// zerolog.SetGlobalLevel under -race (observed 2026-05-05).
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
c.reloadMu.Lock()
|
||||
c.watcherStopped = true
|
||||
c.reloadMu.Unlock()
|
||||
log.Info().Msg("Config hot-reload watcher stopped")
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user