@ -37,7 +37,7 @@ type Rule interface {
// It has no effect if the rule has not yet been Run, or if the rule is Stopped.
// It has no effect if the rule has not yet been Run, or if the rule is Stopped.
Eval ( eval * Evaluation ) ( bool , * Evaluation )
Eval ( eval * Evaluation ) ( bool , * Evaluation )
// Update sends a singal to change the definition of the rule.
// Update sends a singal to change the definition of the rule.
Update ( lastVersion RuleVersionAndPauseStatus ) bool
Update ( eval * Evaluation ) bool
// Type gives the type of the rule.
// Type gives the type of the rule.
Type ( ) ngmodels . RuleType
Type ( ) ngmodels . RuleType
// Status indicates the status of the evaluating rule.
// Status indicates the status of the evaluating rule.
@ -59,7 +59,6 @@ func newRuleFactory(
sender AlertsSender ,
sender AlertsSender ,
stateManager * state . Manager ,
stateManager * state . Manager ,
evalFactory eval . EvaluatorFactory ,
evalFactory eval . EvaluatorFactory ,
ruleProvider ruleProvider ,
clock clock . Clock ,
clock clock . Clock ,
rrCfg setting . RecordingRuleSettings ,
rrCfg setting . RecordingRuleSettings ,
met * metrics . Scheduler ,
met * metrics . Scheduler ,
@ -95,7 +94,6 @@ func newRuleFactory(
sender ,
sender ,
stateManager ,
stateManager ,
evalFactory ,
evalFactory ,
ruleProvider ,
clock ,
clock ,
met ,
met ,
logger ,
logger ,
@ -109,15 +107,11 @@ func newRuleFactory(
type evalAppliedFunc = func ( ngmodels . AlertRuleKey , time . Time )
type evalAppliedFunc = func ( ngmodels . AlertRuleKey , time . Time )
type stopAppliedFunc = func ( ngmodels . AlertRuleKey )
type stopAppliedFunc = func ( ngmodels . AlertRuleKey )
type ruleProvider interface {
get ( ngmodels . AlertRuleKey ) * ngmodels . AlertRule
}
type alertRule struct {
type alertRule struct {
key ngmodels . AlertRuleKeyWithGroup
key ngmodels . AlertRuleKeyWithGroup
evalCh chan * Evaluation
evalCh chan * Evaluation
updateCh chan RuleVersionAndPauseStatus
updateCh chan * Evaluation
ctx context . Context
ctx context . Context
stopFn util . CancelCauseFunc
stopFn util . CancelCauseFunc
@ -129,7 +123,6 @@ type alertRule struct {
sender AlertsSender
sender AlertsSender
stateManager * state . Manager
stateManager * state . Manager
evalFactory eval . EvaluatorFactory
evalFactory eval . EvaluatorFactory
ruleProvider ruleProvider
// Event hooks that are only used in tests.
// Event hooks that are only used in tests.
evalAppliedHook evalAppliedFunc
evalAppliedHook evalAppliedFunc
@ -149,7 +142,6 @@ func newAlertRule(
sender AlertsSender ,
sender AlertsSender ,
stateManager * state . Manager ,
stateManager * state . Manager ,
evalFactory eval . EvaluatorFactory ,
evalFactory eval . EvaluatorFactory ,
ruleProvider ruleProvider ,
clock clock . Clock ,
clock clock . Clock ,
met * metrics . Scheduler ,
met * metrics . Scheduler ,
logger log . Logger ,
logger log . Logger ,
@ -161,7 +153,7 @@ func newAlertRule(
return & alertRule {
return & alertRule {
key : key ,
key : key ,
evalCh : make ( chan * Evaluation ) ,
evalCh : make ( chan * Evaluation ) ,
updateCh : make ( chan RuleVersionAndPauseStatus ) ,
updateCh : make ( chan * Evaluation ) ,
ctx : ctx ,
ctx : ctx ,
stopFn : stop ,
stopFn : stop ,
appURL : appURL ,
appURL : appURL ,
@ -171,7 +163,6 @@ func newAlertRule(
sender : sender ,
sender : sender ,
stateManager : stateManager ,
stateManager : stateManager ,
evalFactory : evalFactory ,
evalFactory : evalFactory ,
ruleProvider : ruleProvider ,
evalAppliedHook : evalAppliedHook ,
evalAppliedHook : evalAppliedHook ,
stopAppliedHook : stopAppliedHook ,
stopAppliedHook : stopAppliedHook ,
metrics : met ,
metrics : met ,
@ -220,7 +211,7 @@ func (a *alertRule) Eval(eval *Evaluation) (bool, *Evaluation) {
}
}
// update sends an instruction to the rule evaluation routine to update the scheduled rule to the specified version. The specified version must be later than the current version, otherwise no update will happen.
// update sends an instruction to the rule evaluation routine to update the scheduled rule to the specified version. The specified version must be later than the current version, otherwise no update will happen.
func ( a * alertRule ) Update ( lastVersion RuleVersionAndPauseStatus ) bool {
func ( a * alertRule ) Update ( eval * Evaluation ) bool {
// check if the channel is not empty.
// check if the channel is not empty.
select {
select {
case <- a . updateCh :
case <- a . updateCh :
@ -230,7 +221,7 @@ func (a *alertRule) Update(lastVersion RuleVersionAndPauseStatus) bool {
}
}
select {
select {
case a . updateCh <- lastVersion :
case a . updateCh <- eval :
return true
return true
case <- a . ctx . Done ( ) :
case <- a . ctx . Done ( ) :
return false
return false
@ -254,15 +245,16 @@ func (a *alertRule) Run() error {
select {
select {
// used by external services (API) to notify that rule is updated.
// used by external services (API) to notify that rule is updated.
case ctx := <- a . updateCh :
case ctx := <- a . updateCh :
if currentFingerprint == ctx . Fingerprint {
fp := ctx . Fingerprint ( )
if currentFingerprint == fp {
a . logger . Info ( "Rule's fingerprint has not changed. Skip resetting the state" , "currentFingerprint" , currentFingerprint )
a . logger . Info ( "Rule's fingerprint has not changed. Skip resetting the state" , "currentFingerprint" , currentFingerprint )
continue
continue
}
}
a . logger . Info ( "Clearing the state of the rule because it was updated" , "isPaused" , ctx . IsPaused , "fingerprint" , ctx . Fingerprint )
a . logger . Info ( "Clearing the state of the rule because it was updated" , "isPaused" , ctx . rule . IsPaused , "fingerprint" , fp )
// clear the state. So the next evaluation will start from the scratch.
// clear the state. So the next evaluation will start from the scratch.
a . resetState ( grafanaCtx , ctx . IsPaused )
a . resetState ( grafanaCtx , ctx . rule , ctx . rule . IsPaused )
currentFingerprint = ctx . Fingerprint
currentFingerprint = fp
// evalCh - used by the scheduler to signal that evaluation is needed.
// evalCh - used by the scheduler to signal that evaluation is needed.
case ctx , ok := <- a . evalCh :
case ctx , ok := <- a . evalCh :
if ! ok {
if ! ok {
@ -298,7 +290,7 @@ func (a *alertRule) Run() error {
// lingers in DB and won't be cleaned up until next alert rule update.
// lingers in DB and won't be cleaned up until next alert rule update.
needReset = needReset || ( currentFingerprint == 0 && isPaused )
needReset = needReset || ( currentFingerprint == 0 && isPaused )
if needReset {
if needReset {
a . resetState ( grafanaCtx , isPaused )
a . resetState ( grafanaCtx , ctx . rule , isPaused )
}
}
currentFingerprint = f
currentFingerprint = f
if isPaused {
if isPaused {
@ -494,8 +486,7 @@ func (a *alertRule) expireAndSend(ctx context.Context, states []state.StateTrans
}
}
}
}
func ( a * alertRule ) resetState ( ctx context . Context , isPaused bool ) {
func ( a * alertRule ) resetState ( ctx context . Context , rule * ngmodels . AlertRule , isPaused bool ) {
rule := a . ruleProvider . get ( a . key . AlertRuleKey )
reason := ngmodels . StateReasonUpdated
reason := ngmodels . StateReasonUpdated
if isPaused {
if isPaused {
reason = ngmodels . StateReasonPaused
reason = ngmodels . StateReasonPaused