Skip to content

Commit

Permalink
Silence limits as functions (#3885)
Browse files Browse the repository at this point in the history
* Silence limits as functions

This commit changes silence limits from a struct of ints to a struct
of functions that return individual limits. This allows limits
to be lazy-loaded and updated without having to call silences.New().

Signed-off-by: George Robinson <george.robinson@grafana.com>

* Add explicit test for no limits

Signed-off-by: George Robinson <george.robinson@grafana.com>

* Fix run()

Signed-off-by: George Robinson <george.robinson@grafana.com>

---------

Signed-off-by: George Robinson <george.robinson@grafana.com>
  • Loading branch information
grobinson-grafana authored Jun 20, 2024
1 parent db32fab commit 124da34
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 11 deletions.
4 changes: 2 additions & 2 deletions cmd/alertmanager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ func run() int {
SnapshotFile: filepath.Join(*dataDir, "silences"),
Retention: *retention,
Limits: silence.Limits{
MaxSilences: *maxSilences,
MaxPerSilenceBytes: *maxPerSilenceBytes,
MaxSilences: func() int { return *maxSilences },
MaxPerSilenceBytes: func() int { return *maxPerSilenceBytes },
},
Logger: log.With(logger, "component", "silences"),
Metrics: prometheus.DefaultRegisterer,
Expand Down
17 changes: 10 additions & 7 deletions silence/silence.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,10 @@ type Silences struct {
type Limits struct {
// MaxSilences limits the maximum number of silences, including expired
// silences.
MaxSilences int
MaxSilences func() int
// MaxPerSilenceBytes is the maximum size of an individual silence as
// stored on disk.
MaxPerSilenceBytes int
MaxPerSilenceBytes func() int
}

// MaintenanceFunc represents the function to run as part of the periodic maintenance for silences.
Expand Down Expand Up @@ -585,8 +585,11 @@ func (s *Silences) setSilence(sil *pb.Silence, now time.Time, skipValidate bool)
// Check the limit unless the silence has been expired. This is to avoid
// situations where silences cannot be expired after the limit has been
// reduced.
if n := msil.Size(); s.limits.MaxPerSilenceBytes > 0 && n > s.limits.MaxPerSilenceBytes && sil.EndsAt.After(now) {
return fmt.Errorf("silence exceeded maximum size: %d bytes (limit: %d bytes)", n, s.limits.MaxPerSilenceBytes)
if s.limits.MaxPerSilenceBytes != nil {
n := msil.Size()
if m := s.limits.MaxPerSilenceBytes(); m > 0 && n > m && sil.EndsAt.After(now) {
return fmt.Errorf("silence exceeded maximum size: %d bytes (limit: %d bytes)", n, m)
}
}

if s.st.merge(msil, now) {
Expand Down Expand Up @@ -622,9 +625,9 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) {
}

// If we got here it's either a new silence or a replacing one.
if s.limits.MaxSilences > 0 {
if len(s.st)+1 > s.limits.MaxSilences {
return "", fmt.Errorf("exceeded maximum number of silences: %d (limit: %d)", len(s.st), s.limits.MaxSilences)
if s.limits.MaxSilences != nil {
if m := s.limits.MaxSilences(); m > 0 && len(s.st)+1 > m {
return "", fmt.Errorf("exceeded maximum number of silences: %d (limit: %d)", len(s.st), m)
}
}

Expand Down
22 changes: 20 additions & 2 deletions silence/silence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,8 @@ func TestSilenceSet(t *testing.T) {
func TestSilenceLimits(t *testing.T) {
s, err := New(Options{
Limits: Limits{
MaxSilences: 1,
MaxPerSilenceBytes: 2 << 11, // 4KB
MaxSilences: func() int { return 1 },
MaxPerSilenceBytes: func() int { return 2 << 11 }, // 4KB
},
})
require.NoError(t, err)
Expand Down Expand Up @@ -535,6 +535,24 @@ func TestSilenceLimits(t *testing.T) {
require.Equal(t, "", id3)
}

func TestSilenceNoLimits(t *testing.T) {
s, err := New(Options{
Limits: Limits{},
})
require.NoError(t, err)

// Insert sil should succeed without error.
sil := &pb.Silence{
Matchers: []*pb.Matcher{{Name: "a", Pattern: "b"}},
StartsAt: time.Now(),
EndsAt: time.Now().Add(5 * time.Minute),
Comment: strings.Repeat("c", 2<<9),
}
id, err := s.Set(sil)
require.NoError(t, err)
require.NotEqual(t, "", id)
}

func TestSetActiveSilence(t *testing.T) {
s, err := New(Options{
Retention: time.Hour,
Expand Down

0 comments on commit 124da34

Please sign in to comment.