diff --git a/app/vmalert/rule/alerting.go b/app/vmalert/rule/alerting.go index be50ef1335..da013ec106 100644 --- a/app/vmalert/rule/alerting.go +++ b/app/vmalert/rule/alerting.go @@ -440,14 +440,13 @@ func (ar *AlertingRule) exec(ctx context.Context, ts time.Time, limit int) ([]pr a.KeepFiringSince = time.Time{} continue } - a, err := ar.newAlert(m, ls, start, qFn) + a, err := ar.newAlert(m, ls, ts, qFn) if err != nil { curState.Err = fmt.Errorf("failed to create alert: %w", err) return nil, curState.Err } a.ID = h a.State = notifier.StatePending - a.ActiveAt = ts ar.alerts[h] = a ar.logDebugf(ts, a, "created in state PENDING") } @@ -473,7 +472,7 @@ func (ar *AlertingRule) exec(ctx context.Context, ts time.Time, limit int) ([]pr } // alerts with ar.KeepFiringFor>0 may remain FIRING // even if their expression isn't true anymore - if ts.Sub(a.KeepFiringSince) > ar.KeepFiringFor { + if ts.Sub(a.KeepFiringSince) >= ar.KeepFiringFor { a.State = notifier.StateInactive a.ResolvedAt = ts ar.logDebugf(ts, a, "FIRING => INACTIVE: is absent in current evaluation round") diff --git a/app/vmalert/rule/alerting_test.go b/app/vmalert/rule/alerting_test.go index 5b7fb54045..95539efd49 100644 --- a/app/vmalert/rule/alerting_test.go +++ b/app/vmalert/rule/alerting_test.go @@ -328,14 +328,17 @@ func TestAlertingRule_Exec(t *testing.T) { fq := &datasource.FakeQuerier{} tc.rule.q = fq tc.rule.GroupID = fakeGroup.ID() + ts := time.Now() for i, step := range tc.steps { fq.Reset() fq.Add(step...) - if _, err := tc.rule.exec(context.TODO(), time.Now(), 0); err != nil { + if _, err := tc.rule.exec(context.TODO(), ts, 0); err != nil { t.Fatalf("unexpected err: %s", err) } - // artificial delay between applying steps - time.Sleep(defaultStep) + + // shift the execution timestamp before the next iteration + ts = ts.Add(defaultStep) + if _, ok := tc.expAlerts[i]; !ok { continue }