diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 17cb068..4a3841e 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -601,13 +601,23 @@ func configUpdater(viperNotifyCh chan fsnotify.Event, edm *dnstapMinimiser) { }) t.Stop() - for e = range viperNotifyCh { - // If an event has been recevied this means we now want to - // enable the timer so the function will be called "soon", but - // if more events occur we will reset it again. This allows us - // to wait until events on the file settles down before - // actually calling the update function. - t.Reset(100 * time.Millisecond) + for { + select { + case event, ok := <-viperNotifyCh: + if !ok { + return + } + e = event + // If an event has been recevied this means we now want to + // enable the timer so the function will be called "soon", but + // if more events occur we will reset it again. This allows us + // to wait until events on the file settles down before + // actually calling the update function. + t.Reset(100 * time.Millisecond) + case <-edm.ctx.Done(): + t.Stop() + return + } } } @@ -1158,12 +1168,15 @@ func Run(logger *slog.Logger, loggerLevel *slog.LevelVar) { os.Exit(1) } - viperNotifyCh := make(chan fsnotify.Event) + viperNotifyCh := make(chan fsnotify.Event, 1) go configUpdater(viperNotifyCh, edm) viper.OnConfigChange(func(e fsnotify.Event) { - viperNotifyCh <- e + select { + case viperNotifyCh <- e: + default: + } }) pdbDir := filepath.Join(startConf.DataDir, "pebble") @@ -1415,6 +1428,8 @@ func Run(logger *slog.Logger, loggerLevel *slog.LevelVar) { edm.log.Info("Run: waiting for other workers to exit") wg.Wait() + close(viperNotifyCh) + // Wait for graceful disconnection from MQTT bus if !startConf.DisableMQTT { edm.log.Info("Run: waiting on MQTT disconnection") diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 2bbe84b..bd813ba 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -10,10 +10,12 @@ import ( "os" "slices" "strings" + "sync" "testing" "time" dnstap "github.com/dnstap/golang-dnstap" + "github.com/fsnotify/fsnotify" "github.com/miekg/dns" "github.com/parquet-go/parquet-go" "github.com/parquet-go/parquet-go/format" @@ -2145,3 +2147,35 @@ func TestWriteHistogramParquetExplicitThreshold(t *testing.T) { } } } +func TestConfigUpdaterExitsOnContextCancel(t *testing.T) { + logger := slog.New(slog.NewTextHandler(io.Discard, nil)) + edm, err := newDnstapMinimiser(logger, defaultTC) + if err != nil { + t.Fatalf("newDnstapMinimiser: %s", err) + } + t.Cleanup(edm.stop) + + viperNotifyCh := make(chan fsnotify.Event, 1) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + configUpdater(viperNotifyCh, edm) + }() + + time.Sleep(50 * time.Millisecond) + + edm.stop() + + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + case <-time.After(2 * time.Second): + t.Fatal("configUpdater did not exit after context cancel") + } +}