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)
|
type Mutator[T any] func(*T)
|
||||||
|
|
||||||
// CopyNotificationSettings creates a deep copy of NotificationSettings.
|
// CopyNotificationSettings creates a deep copy of NotificationSettings.
|
||||||
|
|||||||
@@ -364,10 +364,10 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
|||||||
|
|
||||||
query := strings.Builder{}
|
query := strings.Builder{}
|
||||||
placeholders := make([]string, 0, len(batch))
|
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("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 {
|
for _, instance := range batch {
|
||||||
if err := models.ValidateAlertInstance(instance); err != nil {
|
if err := models.ValidateAlertInstance(instance); err != nil {
|
||||||
@@ -387,7 +387,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?)")
|
placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
|
||||||
args = append(args,
|
args = append(args,
|
||||||
instance.RuleOrgID,
|
instance.RuleOrgID,
|
||||||
instance.RuleUID,
|
instance.RuleUID,
|
||||||
@@ -401,6 +401,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [
|
|||||||
nullableTimeToUnix(instance.FiredAt),
|
nullableTimeToUnix(instance.FiredAt),
|
||||||
nullableTimeToUnix(instance.ResolvedAt),
|
nullableTimeToUnix(instance.ResolvedAt),
|
||||||
nullableTimeToUnix(instance.LastSentAt),
|
nullableTimeToUnix(instance.LastSentAt),
|
||||||
|
instance.ResultFingerprint,
|
||||||
annotationsJSON,
|
annotationsJSON,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/snappy"
|
"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/grafana/grafana/pkg/util/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/protobuf/proto"
|
"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) {
|
t.Run("Should save all instances when batch size is bigger than 1", func(t *testing.T) {
|
||||||
batchSize = 2
|
batchSize = 2
|
||||||
newRuleUID := "y"
|
testInstances := []models.AlertInstance{
|
||||||
err := ng.InstanceStore.FullSync(ctx, append(instances, *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID(newRuleUID))), batchSize, nil)
|
*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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
res, err := ng.InstanceStore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{
|
res, err := ng.InstanceStore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{
|
||||||
RuleOrgID: orgID,
|
RuleOrgID: orgID,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, res, len(instances)+1)
|
|
||||||
for _, ruleUID := range append(ruleUIDs, newRuleUID) {
|
savedInstances := make([]models.AlertInstance, len(res))
|
||||||
found := false
|
for i, r := range res {
|
||||||
for _, instance := range res {
|
savedInstances[i] = *r
|
||||||
if instance.RuleUID == ruleUID {
|
|
||||||
found = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Errorf("Instance with RuleUID '%s' not found", ruleUID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
t.Run("Should not fail when the instances are empty", func(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user