Files
dance-lessons-coach/pkg
Gabriel Radureau 189d44d70f
All checks were successful
CI/CD Pipeline / Build Docker Cache (push) Successful in 24s
CI/CD Pipeline / CI Pipeline (push) Successful in 7m36s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped
🔧 chore(config): defense-in-depth for the WatchAndApply test race (Q-038)
Follow-up to PR #48 after user question on whether mutex/atomic would be
a cleaner fix than removing the log call.

Honest answer: the racing memory location is zerolog's global gLevel,
which IS already mutated atomically by zerolog itself. The race detector
flags it because LoadConfig → SetupLogging writes gLevel via
zerolog.SetGlobalLevel and a leaked watcher goroutine reads gLevel via
log.Info() — both atomic individually, but go test -race treats the
write/read pair as a happens-before violation across goroutine
boundaries when there's no synchronization between them.

A mutex on Config would not help: the shared state isn't on Config,
it's on zerolog's package-level global. atomic.Pointer wouldn't help
for the same reason.

Combined fix:
1. Keep the log-removal (PR #48) — it's the actual race source: our
   cancel-handler goroutine's log.Info("watcher stopped") was the
   reading party. Add a longer comment explaining WHY it's gone.
2. Add pkg/config/main_test.go with TestMain that disables zerolog
   globally during the test suite. Defense in depth: any FUTURE
   leaked log call from a watcher-related goroutine won't trigger a
   race either, because no log call evaluates against the level.

Production behavior unchanged. SetupLogging in production runs once at
startup before any goroutine could race with it.

go test -race -count=2 ./pkg/config/... passes (was failing).
2026-05-05 09:44:58 +02:00
..