Files
mathieuHaandClaude Opus 5.5 efaa617e6d 🐛 keep the stream and metrics tickers on their own channels (#399)
Traefik runs the plugin under yaegi, which shares the case list of a
select statement between every goroutine that runs it. Both ticker
loops ran the same select, so when the tickers fired together one loop
could end up waiting on the other's channel, dropping stream ticks for
up to two metrics intervals.

Range over the ticker channel instead, which yaegi evaluates per
execution. The stop channel was never used.

Fixes #377

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:57:12 +02:00

38 lines
913 B
Go

package crowdsec_bouncer_traefik_plugin //nolint:revive,stylecheck
import (
"sync"
"sync/atomic"
"testing"
"time"
)
func sendTicks(ticks chan time.Time, count int) {
for i := 0; i < count; i++ { //nolint:intrange
ticks <- time.Time{}
}
}
func Test_runTicker_keepsEachTickerOnItsOwnChannel(t *testing.T) {
const count = 20000
var streamRuns, metricsRuns int64
var runs sync.WaitGroup
runs.Add(2 * count)
streamTicks := make(chan time.Time)
metricsTicks := make(chan time.Time)
go runTicker(streamTicks, func() {
atomic.AddInt64(&streamRuns, 1)
runs.Done()
})
go runTicker(metricsTicks, func() {
atomic.AddInt64(&metricsRuns, 1)
runs.Done()
})
go sendTicks(streamTicks, count)
go sendTicks(metricsTicks, count)
runs.Wait()
if streamRuns != count || metricsRuns != count {
t.Errorf("runTicker ran stream %d and metrics %d times, want %d each", streamRuns, metricsRuns, count)
}
}