Prior to this change, all alert instance writes and deletes happened
individually, in their own database transaction. This change batches up
writes or deletes for a given rule's evaluation loop into a single
transaction before applying it.
These new transactions are off by default, guarded by the feature toggle "alertingBigTransactions"
Before:
```
goos: darwin
goarch: arm64
pkg: github.com/grafana/grafana/pkg/services/ngalert/store
BenchmarkAlertInstanceOperations-8 398 2991381 ns/op 1133537 B/op 27703 allocs/op
--- BENCH: BenchmarkAlertInstanceOperations-8
util.go:127: alert definition: {orgID: 1, UID: FovKXiRVzm} with title: "an alert definition FTvFXmRVkz" interval: 60 created
util.go:127: alert definition: {orgID: 1, UID: foDFXmRVkm} with title: "an alert definition fovFXmRVkz" interval: 60 created
util.go:127: alert definition: {orgID: 1, UID: VQvFuigVkm} with title: "an alert definition VwDKXmR4kz" interval: 60 created
PASS
ok github.com/grafana/grafana/pkg/services/ngalert/store 1.619s
```
After:
```
goos: darwin
goarch: arm64
pkg: github.com/grafana/grafana/pkg/services/ngalert/store
BenchmarkAlertInstanceOperations-8 1440 816484 ns/op 352297 B/op 6529 allocs/op
--- BENCH: BenchmarkAlertInstanceOperations-8
util.go:127: alert definition: {orgID: 1, UID: 302r_igVzm} with title: "an alert definition q0h9lmR4zz" interval: 60 created
util.go:127: alert definition: {orgID: 1, UID: 71hrlmR4km} with title: "an alert definition nJ29_mR4zz" interval: 60 created
util.go:127: alert definition: {orgID: 1, UID: Cahr_mR4zm} with title: "an alert definition ja2rlmg4zz" interval: 60 created
PASS
ok github.com/grafana/grafana/pkg/services/ngalert/store 1.383s
```
So we cut time by about 75% and memory allocations by about 60% when
storing and deleting 100 instances.
78 lines
2.1 KiB
Go
78 lines
2.1 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// AlertInstance represents a single alert instance.
|
|
type AlertInstance struct {
|
|
AlertInstanceKey `xorm:"extends"`
|
|
Labels InstanceLabels
|
|
CurrentState InstanceStateType
|
|
CurrentReason string
|
|
CurrentStateSince time.Time
|
|
CurrentStateEnd time.Time
|
|
LastEvalTime time.Time
|
|
}
|
|
|
|
type AlertInstanceKey struct {
|
|
RuleOrgID int64 `xorm:"rule_org_id"`
|
|
RuleUID string `xorm:"rule_uid"`
|
|
LabelsHash string
|
|
}
|
|
|
|
// InstanceStateType is an enum for instance states.
|
|
type InstanceStateType string
|
|
|
|
const (
|
|
// InstanceStateFiring is for a firing alert.
|
|
InstanceStateFiring InstanceStateType = "Alerting"
|
|
// InstanceStateNormal is for a normal alert.
|
|
InstanceStateNormal InstanceStateType = "Normal"
|
|
// InstanceStatePending is for an alert that is firing but has not met the duration
|
|
InstanceStatePending InstanceStateType = "Pending"
|
|
// InstanceStateNoData is for an alert with no data.
|
|
InstanceStateNoData InstanceStateType = "NoData"
|
|
// InstanceStateError is for a erroring alert.
|
|
InstanceStateError InstanceStateType = "Error"
|
|
)
|
|
|
|
// IsValid checks that the value of InstanceStateType is a valid
|
|
// string.
|
|
func (i InstanceStateType) IsValid() bool {
|
|
return i == InstanceStateFiring ||
|
|
i == InstanceStateNormal ||
|
|
i == InstanceStateNoData ||
|
|
i == InstanceStatePending ||
|
|
i == InstanceStateError
|
|
}
|
|
|
|
// ListAlertInstancesQuery is the query list alert Instances.
|
|
type ListAlertInstancesQuery struct {
|
|
RuleOrgID int64 `json:"-"`
|
|
RuleUID string
|
|
State InstanceStateType
|
|
StateReason string
|
|
|
|
Result []*AlertInstance
|
|
}
|
|
|
|
// ValidateAlertInstance validates that the alert instance contains an alert rule id,
|
|
// and state.
|
|
func ValidateAlertInstance(alertInstance AlertInstance) error {
|
|
if alertInstance.RuleOrgID == 0 {
|
|
return fmt.Errorf("alert instance is invalid due to missing alert rule organisation")
|
|
}
|
|
|
|
if alertInstance.RuleUID == "" {
|
|
return fmt.Errorf("alert instance is invalid due to missing alert rule uid")
|
|
}
|
|
|
|
if !alertInstance.CurrentState.IsValid() {
|
|
return fmt.Errorf("alert instance is invalid because the state '%v' is invalid", alertInstance.CurrentState)
|
|
}
|
|
|
|
return nil
|
|
}
|