mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
5bbe9c6e61
* remove jitter feature flag * Add an out so users can manually disable jitter * Pass in cfg * Add TODO to remove knob in future
71 lines
2.2 KiB
Go
71 lines
2.2 KiB
Go
package schedule
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
// JitterStrategy represents a modifier to alert rule timing that affects how evaluations are distributed.
|
|
type JitterStrategy int
|
|
|
|
const (
|
|
JitterNever JitterStrategy = iota
|
|
JitterByGroup
|
|
JitterByRule
|
|
)
|
|
|
|
// JitterStrategyFrom returns the JitterStrategy indicated by the current Grafana feature toggles.
|
|
func JitterStrategyFrom(cfg setting.UnifiedAlertingSettings, toggles featuremgmt.FeatureToggles) JitterStrategy {
|
|
strategy := JitterByGroup
|
|
if cfg.DisableJitter {
|
|
return JitterNever
|
|
}
|
|
if toggles == nil {
|
|
return strategy
|
|
}
|
|
if toggles.IsEnabledGlobally(featuremgmt.FlagJitterAlertRulesWithinGroups) {
|
|
strategy = JitterByRule
|
|
}
|
|
return strategy
|
|
}
|
|
|
|
// jitterOffsetInTicks gives the jitter offset for a rule, in terms of a number of ticks relative to its interval and a base interval.
|
|
// The resulting number of ticks is non-negative. We assume the rule is well-formed and has an IntervalSeconds greater to or equal than baseInterval.
|
|
func jitterOffsetInTicks(r *ngmodels.AlertRule, baseInterval time.Duration, strategy JitterStrategy) int64 {
|
|
if strategy == JitterNever {
|
|
return 0
|
|
}
|
|
|
|
itemFrequency := r.IntervalSeconds / int64(baseInterval.Seconds())
|
|
offset := jitterHash(r, strategy) % uint64(itemFrequency)
|
|
// Offset is always nonnegative and less than int64.max, because above we mod by itemFrequency which fits in the positive half of int64.
|
|
// offset <= itemFrequency <= int64.max
|
|
// So, this will not overflow and produce a negative offset.
|
|
res := int64(offset)
|
|
|
|
// Regardless, take an absolute value anyway for an extra layer of safety in case the above logic ever changes.
|
|
// Our contract requires that the result is nonnegative and less than int64.max.
|
|
if res < 0 {
|
|
return -res
|
|
}
|
|
return res
|
|
}
|
|
|
|
func jitterHash(r *ngmodels.AlertRule, strategy JitterStrategy) uint64 {
|
|
ls := data.Labels{
|
|
"name": r.RuleGroup,
|
|
"file": r.NamespaceUID,
|
|
"orgId": fmt.Sprint(r.OrgID),
|
|
}
|
|
|
|
if strategy == JitterByRule {
|
|
ls["uid"] = r.UID
|
|
}
|
|
return uint64(ls.Fingerprint())
|
|
}
|