Alerting: Fix saving result_fingerprint in async alert state persister (#115005)
This commit is contained in:
@@ -973,6 +973,12 @@ func (a AlertInstanceMutators) WithAnnotations(annotations InstanceAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AlertInstanceMutators) WithResultFingerprint(fp string) AlertInstanceMutator {
|
||||
return func(i *AlertInstance) {
|
||||
i.ResultFingerprint = fp
|
||||
}
|
||||
}
|
||||
|
||||
type Mutator[T any] func(*T)
|
||||
|
||||
// CopyNotificationSettings creates a deep copy of NotificationSettings.
|
||||
|
||||
@@ -364,10 +364,10 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
||||
|
||||
query := strings.Builder{}
|
||||
placeholders := make([]string, 0, len(batch))
|
||||
args := make([]any, 0, len(batch)*13)
|
||||
args := make([]any, 0, len(batch)*14)
|
||||
|
||||
query.WriteString("INSERT INTO alert_instance ")
|
||||
query.WriteString("(rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, fired_at, resolved_at, last_sent_at, annotations) VALUES ")
|
||||
query.WriteString("(rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, fired_at, resolved_at, last_sent_at, result_fingerprint, annotations) VALUES ")
|
||||
|
||||
for _, instance := range batch {
|
||||
if err := models.ValidateAlertInstance(instance); err != nil {
|
||||
@@ -387,7 +387,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
||||
continue
|
||||
}
|
||||
|
||||
placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?)")
|
||||
placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
|
||||
args = append(args,
|
||||
instance.RuleOrgID,
|
||||
instance.RuleUID,
|
||||
@@ -401,6 +401,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
||||
nullableTimeToUnix(instance.FiredAt),
|
||||
nullableTimeToUnix(instance.ResolvedAt),
|
||||
nullableTimeToUnix(instance.LastSentAt),
|
||||
instance.ResultFingerprint,
|
||||
annotationsJSON,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -391,27 +393,33 @@ func TestIntegrationFullSync(t *testing.T) {
|
||||
|
||||
t.Run("Should save all instances when batch size is bigger than 1", func(t *testing.T) {
|
||||
batchSize = 2
|
||||
newRuleUID := "y"
|
||||
err := ng.InstanceStore.FullSync(ctx, append(instances, *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID(newRuleUID))), batchSize, nil)
|
||||
testInstances := []models.AlertInstance{
|
||||
*models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch1"), models.InstanceMuts.WithResultFingerprint("fp0")),
|
||||
*models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch2"), models.InstanceMuts.WithResultFingerprint("fp1")),
|
||||
*models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch3"), models.InstanceMuts.WithResultFingerprint("fp2")),
|
||||
}
|
||||
|
||||
err := ng.InstanceStore.FullSync(ctx, testInstances, batchSize, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := ng.InstanceStore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{
|
||||
RuleOrgID: orgID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res, len(instances)+1)
|
||||
for _, ruleUID := range append(ruleUIDs, newRuleUID) {
|
||||
found := false
|
||||
for _, instance := range res {
|
||||
if instance.RuleUID == ruleUID {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Instance with RuleUID '%s' not found", ruleUID)
|
||||
}
|
||||
|
||||
savedInstances := make([]models.AlertInstance, len(res))
|
||||
for i, r := range res {
|
||||
savedInstances[i] = *r
|
||||
}
|
||||
|
||||
opts := []cmp.Option{
|
||||
cmpopts.EquateApproxTime(time.Second), // we don't get the same precision back from the DB
|
||||
cmpopts.EquateEmpty(),
|
||||
cmpopts.SortSlices(func(a, b models.AlertInstance) bool {
|
||||
return a.RuleUID < b.RuleUID
|
||||
}),
|
||||
}
|
||||
require.Empty(t, cmp.Diff(testInstances, savedInstances, opts...))
|
||||
})
|
||||
|
||||
t.Run("Should not fail when the instances are empty", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user