Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ require (
github.com/aws/smithy-go v1.27.3
github.com/cenkalti/backoff/v4 v4.3.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/coder/quartz v0.3.1
github.com/coreos/go-systemd/v22 v22.7.0
github.com/emersion/go-smtp v0.24.0
github.com/fsnotify/fsnotify v1.10.1
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,6 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coder/quartz v0.3.1 h1:JMJLj4Xj4NLSrUC1R/g/Hn0y9fkyOvb8tf6P0j+kPn0=
github.com/coder/quartz v0.3.1/go.mod h1:BgE7DOj/8NfvRgvKw0jPLDQH/2Lya2kxcTaNJ8X0rZk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
Expand Down
8 changes: 2 additions & 6 deletions nflog/nflog.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (
"sync"
"time"

"github.com/coder/quartz"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/common/promslog"
Expand Down Expand Up @@ -174,8 +173,6 @@ func (s *Store) Delete(key string) {

// Log holds the notification log state for alerts that have been notified.
type Log struct {
clock quartz.Clock

logger *slog.Logger
metrics *metrics
retention time.Duration
Expand Down Expand Up @@ -347,7 +344,6 @@ func New(o Options) (*Log, error) {
}

l := &Log{
clock: quartz.NewReal(),
retention: o.Retention,
logger: promslog.NewNopLogger(),
st: state{},
Expand Down Expand Up @@ -381,7 +377,7 @@ func New(o Options) (*Log, error) {
}

func (l *Log) now() time.Time {
return l.clock.Now()
return time.Now()
}

// Maintenance garbage collects the notification log state at the given interval. If the snapshot
Expand All @@ -393,7 +389,7 @@ func (l *Log) Maintenance(interval time.Duration, snapf string, stopc <-chan str
l.logger.Error("interval or stop signal are missing - not running maintenance")
return
}
t := l.clock.NewTicker(interval)
t := time.NewTicker(interval)
defer t.Stop()

var doMaintenance MaintenanceFunc
Expand Down
80 changes: 38 additions & 42 deletions nflog/nflog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import (
"sync"
"sync/atomic"
"testing"
"testing/synctest"
"time"

pb "github.com/prometheus/alertmanager/nflog/nflogpb"

"github.com/coder/quartz"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
Expand All @@ -34,8 +34,7 @@ import (
)

func TestLogGC(t *testing.T) {
mockClock := quartz.NewMock(t)
now := mockClock.Now()
now := time.Now()
// We only care about key names and expiration timestamps.
newEntry := func(ts time.Time) *pb.MeshEntry {
return &pb.MeshEntry{
Expand All @@ -49,7 +48,6 @@ func TestLogGC(t *testing.T) {
"a2": newEntry(now.Add(time.Second)),
"a3": newEntry(now.Add(-time.Second)),
},
clock: mockClock,
metrics: newMetrics(prometheus.NewRegistry()),
}
n, err := l.GC()
Expand All @@ -64,8 +62,7 @@ func TestLogGC(t *testing.T) {

func TestLogSnapshot(t *testing.T) {
// Check whether storing and loading the snapshot is symmetric.
mockClock := quartz.NewMock(t)
now := mockClock.Now().UTC()
now := time.Now().UTC()

cases := []struct {
entries []*pb.MeshEntry
Expand Down Expand Up @@ -139,53 +136,54 @@ func TestLogSnapshot(t *testing.T) {
}

func TestWithMaintenance_SupportsCustomCallback(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "snapshot")
require.NoError(t, err, "creating temp file failed")
stopc := make(chan struct{})
reg := prometheus.NewPedanticRegistry()
opts := Options{
Metrics: reg,
SnapshotFile: f.Name(),
}
synctest.Test(t, func(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "snapshot")
require.NoError(t, err, "creating temp file failed")
stopc := make(chan struct{})
reg := prometheus.NewPedanticRegistry()
opts := Options{
Metrics: reg,
SnapshotFile: f.Name(),
}

l, err := New(opts)
clock := quartz.NewMock(t)
l.clock = clock
require.NoError(t, err)
l, err := New(opts)
require.NoError(t, err)

var calls atomic.Int32
var wg sync.WaitGroup
var calls atomic.Int32
var wg sync.WaitGroup

wg.Go(func() {
l.Maintenance(100*time.Millisecond, f.Name(), stopc, func() (int64, error) {
calls.Add(1)
return 0, nil
wg.Go(func() {
l.Maintenance(100*time.Millisecond, f.Name(), stopc, func() (int64, error) {
calls.Add(1)
return 0, nil
})
})
})
gosched()
gosched()

// Before the first tick, no maintenance executed.
clock.Advance(99 * time.Millisecond)
require.EqualValues(t, 0, calls.Load())
// Before the first tick, no maintenance executed.
time.Sleep(99 * time.Millisecond)
require.EqualValues(t, 0, calls.Load())

// Tick once.
clock.Advance(1 * time.Millisecond)
require.Eventually(t, func() bool { return calls.Load() == 1 }, 5*time.Second, time.Second)
// Tick once.
time.Sleep(1 * time.Millisecond)
synctest.Wait()
require.EqualValues(t, 1, calls.Load())

// Stop the maintenance loop. We should get exactly one more execution of the maintenance func.
close(stopc)
wg.Wait()
// Stop the maintenance loop. We should get exactly one more execution of the maintenance func.
close(stopc)
wg.Wait()

require.EqualValues(t, 2, calls.Load())
// Check the maintenance metrics.
require.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(`
require.EqualValues(t, 2, calls.Load())
// Check the maintenance metrics.
require.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(`
# HELP alertmanager_nflog_maintenance_errors_total How many maintenances were executed for the notification log that failed.
# TYPE alertmanager_nflog_maintenance_errors_total counter
alertmanager_nflog_maintenance_errors_total 0
# HELP alertmanager_nflog_maintenance_total How many maintenances were executed for the notification log.
# TYPE alertmanager_nflog_maintenance_total counter
alertmanager_nflog_maintenance_total 2
`), "alertmanager_nflog_maintenance_total", "alertmanager_nflog_maintenance_errors_total"))
})
}

func TestReplaceFile(t *testing.T) {
Expand Down Expand Up @@ -217,8 +215,7 @@ func TestReplaceFile(t *testing.T) {
}

func TestStateMerge(t *testing.T) {
mockClock := quartz.NewMock(t)
now := mockClock.Now()
now := time.Now()

// We only care about key names and timestamps for the
// merging logic.
Expand Down Expand Up @@ -279,8 +276,7 @@ func TestStateMerge(t *testing.T) {

func TestStateDataCoding(t *testing.T) {
// Check whether encoding and decoding the data is symmetric.
mockClock := quartz.NewMock(t)
now := mockClock.Now().UTC()
now := time.Now().UTC()

cases := []struct {
entries []*pb.MeshEntry
Expand Down
10 changes: 3 additions & 7 deletions silence/silence.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"sync"
"time"

"github.com/coder/quartz"
uuid "github.com/google/uuid"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
Expand Down Expand Up @@ -334,8 +333,6 @@ func (s *Silencer) PostGC(ff model.Fingerprints) {

// Silences holds a silence state that can be modified, queried, and snapshot.
type Silences struct {
clock quartz.Clock

logger *slog.Logger
metrics *metrics
retention time.Duration
Expand Down Expand Up @@ -529,7 +526,6 @@ func New(o Options) (*Silences, error) {
}

s := &Silences{
clock: quartz.NewReal(),
mi: make(matcherIndex, 512),
vi: make(versionIndex, 0, 512),
logger: promslog.NewNopLogger(),
Expand Down Expand Up @@ -570,7 +566,7 @@ func New(o Options) (*Silences, error) {
}

func (s *Silences) nowUTC() time.Time {
return s.clock.Now().UTC()
return time.Now().UTC()
}

// updateSizeMetrics updates the size metrics for state, matcher index, and version index.
Expand All @@ -592,7 +588,7 @@ func (s *Silences) Maintenance(interval time.Duration, snapf string, stopc <-cha
s.logger.Error("interval or stop signal are missing - not running maintenance")
return
}
t := s.clock.NewTicker(interval)
t := time.NewTicker(interval)
defer t.Stop()

var doMaintenance MaintenanceFunc
Expand Down Expand Up @@ -630,7 +626,7 @@ func (s *Silences) Maintenance(interval time.Duration, snapf string, stopc <-cha
s.metrics.maintenanceErrorsTotal.Inc()
return err
}
s.logger.Debug("Maintenance done", "duration", s.clock.Since(start), "size", size)
s.logger.Debug("Maintenance done", "duration", time.Since(start), "size", size)
return nil
}

Expand Down
35 changes: 10 additions & 25 deletions silence/silence_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"testing"
"time"

"github.com/coder/quartz"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model"
"github.com/prometheus/common/promslog"
Expand Down Expand Up @@ -71,9 +70,7 @@ func benchmarkMutes(b *testing.B, totalSilences, matchingSilences int) {
silences, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
silences.clock = clock
now := clock.Now()
now := time.Now()

// Calculate interval to intersperse matching silences
var interval int
Expand All @@ -95,7 +92,7 @@ func benchmarkMutes(b *testing.B, totalSilences, matchingSilences int) {
Pattern: "bar",
}},
StartsAt: timestamppb.New(now),
EndsAt: timestamppb.New(now.Add(time.Minute)),
EndsAt: timestamppb.New(now.Add(24 * time.Hour)),
}
matchingCreated++
} else {
Expand All @@ -107,7 +104,7 @@ func benchmarkMutes(b *testing.B, totalSilences, matchingSilences int) {
Pattern: "job" + strconv.Itoa(i),
}},
StartsAt: timestamppb.New(now),
EndsAt: timestamppb.New(now.Add(time.Minute)),
EndsAt: timestamppb.New(now.Add(24 * time.Hour)),
}
}
require.NoError(b, silences.Set(b.Context(), s))
Expand Down Expand Up @@ -140,9 +137,7 @@ func BenchmarkMutesIncremental(b *testing.B) {
silences, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
silences.clock = clock
now := clock.Now()
now := time.Now()

// Create base set of silences - most don't match, some do
// This simulates a realistic production scenario
Expand Down Expand Up @@ -263,9 +258,7 @@ func benchmarkQuery(b *testing.B, numSilences int) {
s, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
s.clock = clock
now := clock.Now()
now := time.Now()

lset := model.LabelSet{"aaaa": "AAAA", "bbbb": "BBBB", "cccc": "CCCC"}

Expand Down Expand Up @@ -332,9 +325,7 @@ func benchmarkQueryParallel(b *testing.B, numSilences int) {
s, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
s.clock = clock
now := clock.Now()
now := time.Now()

lset := model.LabelSet{"aaaa": "AAAA", "bbbb": "BBBB", "cccc": "CCCC"}

Expand Down Expand Up @@ -413,9 +404,7 @@ func benchmarkQueryWithConcurrentAdds(b *testing.B, initialSilences int, addRati
s, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
s.clock = clock
now := clock.Now()
now := time.Now()

lset := model.LabelSet{"aaaa": "AAAA", "bbbb": "BBBB", "cccc": "CCCC"}

Expand Down Expand Up @@ -508,9 +497,7 @@ func benchmarkMutesParallel(b *testing.B, numSilences int) {
silences, err := New(Options{Metrics: prometheus.NewRegistry()})
require.NoError(b, err)

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
silences.clock = clock
now := clock.Now()
now := time.Now()

// Create silences that will match the alert
for range numSilences {
Expand All @@ -521,7 +508,7 @@ func benchmarkMutesParallel(b *testing.B, numSilences int) {
Pattern: "bar",
}},
StartsAt: timestamppb.New(now),
EndsAt: timestamppb.New(now.Add(time.Minute)),
EndsAt: timestamppb.New(now.Add(24 * time.Hour)),
}
require.NoError(b, silences.Set(b.Context(), s))
}
Expand Down Expand Up @@ -567,8 +554,7 @@ func BenchmarkGC(b *testing.B) {
func benchmarkGC(b *testing.B, numSilences int, expiredRatio float64) {
b.ReportAllocs()

clock := quartz.NewMock(b).WithLogger(quartz.NoOpLogger)
now := clock.Now()
now := time.Now()

numExpired := int(float64(numSilences) * expiredRatio)
numActive := numSilences - numExpired
Expand Down Expand Up @@ -623,7 +609,6 @@ func benchmarkGC(b *testing.B, numSilences int, expiredRatio float64) {
Metrics: prometheus.NewRegistry(),
})
require.NoError(b, err)
s.clock = clock

for _, sil := range sils {
s.st[sil.Silence.Id] = sil
Expand Down
Loading
Loading