initial rename refactoring

This commit is contained in:
bergquist 2018-09-26 17:26:02 +02:00
parent 869e36995a
commit ff79f80685
8 changed files with 81 additions and 106 deletions

View File

@ -76,33 +76,36 @@ type GetAllAlertNotificationsQuery struct {
Result []*AlertNotification Result []*AlertNotification
} }
type AlertNotificationJournal struct { type AlertNotificationState struct {
Id int64 Id int64
OrgId int64 OrgId int64
AlertId int64 AlertId int64
NotifierId int64 NotifierId int64
SentAt int64 SentAt int64
Success bool State string
Version int64
} }
type RecordNotificationJournalCommand struct { type UpdateAlertNotificationStateCommand struct {
OrgId int64 OrgId int64
AlertId int64 AlertId int64
NotifierId int64 NotifierId int64
SentAt int64 SentAt int64
Success bool State bool
} }
type GetLatestNotificationQuery struct { type GetNotificationStateQuery struct {
OrgId int64 OrgId int64
AlertId int64 AlertId int64
NotifierId int64 NotifierId int64
Result []AlertNotificationJournal Result *AlertNotificationState
} }
type CleanNotificationJournalCommand struct { type InsertAlertNotificationCommand struct {
OrgId int64 OrgId int64
AlertId int64 AlertId int64
NotifierId int64 NotifierId int64
SentAt int64
State string
} }

View File

@ -4,12 +4,10 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"time"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/imguploader" "github.com/grafana/grafana/pkg/components/imguploader"
"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@ -68,30 +66,31 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi
// Verify that we can send the notification again // Verify that we can send the notification again
// but this time within the same transaction. // but this time within the same transaction.
if !evalContext.IsTestRun && !not.ShouldNotify(ctx, evalContext) { // if !evalContext.IsTestRun && !not.ShouldNotify(ctx, evalContext) {
return nil // return nil
} // }
n.log.Debug("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault()) // n.log.Debug("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault())
metrics.M_Alerting_Notification_Sent.WithLabelValues(not.GetType()).Inc() // metrics.M_Alerting_Notification_Sent.WithLabelValues(not.GetType()).Inc()
//send notification // //send notification
success := not.Notify(evalContext) == nil // // success := not.Notify(evalContext) == nil
if evalContext.IsTestRun { // if evalContext.IsTestRun {
return nil // return nil
} // }
//write result to db. //write result to db.
cmd := &m.RecordNotificationJournalCommand{ // cmd := &m.RecordNotificationJournalCommand{
OrgId: evalContext.Rule.OrgId, // OrgId: evalContext.Rule.OrgId,
AlertId: evalContext.Rule.Id, // AlertId: evalContext.Rule.Id,
NotifierId: not.GetNotifierId(), // NotifierId: not.GetNotifierId(),
SentAt: time.Now().Unix(), // SentAt: time.Now().Unix(),
Success: success, // Success: success,
} // }
return bus.DispatchCtx(ctx, cmd) // return bus.DispatchCtx(ctx, cmd)
return nil
}) })
if err != nil { if err != nil {

View File

@ -42,22 +42,23 @@ func NewNotifierBase(model *models.AlertNotification) NotifierBase {
} }
} }
func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequency time.Duration, journals []models.AlertNotificationJournal) bool { func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequency time.Duration, notificationState *models.AlertNotificationState) bool {
// Only notify on state change. // Only notify on state change.
if context.PrevAlertState == context.Rule.State && !sendReminder { if context.PrevAlertState == context.Rule.State && !sendReminder {
return false return false
} }
// get last successfully sent notification // get last successfully sent notification
lastNotify := time.Time{} // lastNotify := time.Time{}
for _, j := range journals { // for _, j := range journals {
if j.Success { // if j.Success {
lastNotify = time.Unix(j.SentAt, 0) // lastNotify = time.Unix(j.SentAt, 0)
break // break
} // }
} // }
// Do not notify if interval has not elapsed // Do not notify if interval has not elapsed
lastNotify := time.Unix(notificationState.SentAt, 0)
if sendReminder && !lastNotify.IsZero() && lastNotify.Add(frequency).After(time.Now()) { if sendReminder && !lastNotify.IsZero() && lastNotify.Add(frequency).After(time.Now()) {
return false return false
} }
@ -77,7 +78,7 @@ func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequ
// ShouldNotify checks this evaluation should send an alert notification // ShouldNotify checks this evaluation should send an alert notification
func (n *NotifierBase) ShouldNotify(ctx context.Context, c *alerting.EvalContext) bool { func (n *NotifierBase) ShouldNotify(ctx context.Context, c *alerting.EvalContext) bool {
cmd := &models.GetLatestNotificationQuery{ cmd := &models.GetNotificationStateQuery{
OrgId: c.Rule.OrgId, OrgId: c.Rule.OrgId,
AlertId: c.Rule.Id, AlertId: c.Rule.Id,
NotifierId: n.Id, NotifierId: n.Id,

View File

@ -23,7 +23,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState m.AlertStateType newState m.AlertStateType
sendReminder bool sendReminder bool
frequency time.Duration frequency time.Duration
journals []m.AlertNotificationJournal journals *m.AlertNotificationState
expect bool expect bool
}{ }{
@ -32,7 +32,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStatePending, newState: m.AlertStatePending,
prevState: m.AlertStateOK, prevState: m.AlertStateOK,
sendReminder: false, sendReminder: false,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: false, expect: false,
}, },
@ -41,7 +41,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStateOK, newState: m.AlertStateOK,
prevState: m.AlertStateAlerting, prevState: m.AlertStateAlerting,
sendReminder: false, sendReminder: false,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: true, expect: true,
}, },
@ -50,7 +50,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStateOK, newState: m.AlertStateOK,
prevState: m.AlertStatePending, prevState: m.AlertStatePending,
sendReminder: false, sendReminder: false,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: false, expect: false,
}, },
@ -59,7 +59,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStateOK, newState: m.AlertStateOK,
prevState: m.AlertStateOK, prevState: m.AlertStateOK,
sendReminder: false, sendReminder: false,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: false, expect: false,
}, },
@ -68,7 +68,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStateOK, newState: m.AlertStateOK,
prevState: m.AlertStateAlerting, prevState: m.AlertStateAlerting,
sendReminder: true, sendReminder: true,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: true, expect: true,
}, },
@ -77,7 +77,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
newState: m.AlertStateOK, newState: m.AlertStateOK,
prevState: m.AlertStateOK, prevState: m.AlertStateOK,
sendReminder: true, sendReminder: true,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: false, expect: false,
}, },
@ -87,7 +87,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
prevState: m.AlertStateAlerting, prevState: m.AlertStateAlerting,
frequency: time.Minute * 10, frequency: time.Minute * 10,
sendReminder: true, sendReminder: true,
journals: []m.AlertNotificationJournal{}, journals: &m.AlertNotificationState{},
expect: true, expect: true,
}, },
@ -97,9 +97,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
prevState: m.AlertStateAlerting, prevState: m.AlertStateAlerting,
frequency: time.Minute * 10, frequency: time.Minute * 10,
sendReminder: true, sendReminder: true,
journals: []m.AlertNotificationJournal{ journals: &m.AlertNotificationState{SentAt: tnow.Add(-time.Minute).Unix()},
{SentAt: tnow.Add(-time.Minute).Unix(), Success: true},
},
expect: false, expect: false,
}, },
@ -110,10 +108,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
frequency: time.Minute * 10, frequency: time.Minute * 10,
sendReminder: true, sendReminder: true,
expect: true, expect: true,
journals: []m.AlertNotificationJournal{ journals: &m.AlertNotificationState{SentAt: tnow.Add(-time.Hour).Unix()},
{SentAt: tnow.Add(-time.Minute).Unix(), Success: false}, // recent failed notification
{SentAt: tnow.Add(-time.Hour).Unix(), Success: true}, // old successful notification
},
}, },
} }
@ -142,7 +137,7 @@ func TestShouldNotifyWhenNoJournalingIsFound(t *testing.T) {
evalContext := alerting.NewEvalContext(context.TODO(), &alerting.Rule{}) evalContext := alerting.NewEvalContext(context.TODO(), &alerting.Rule{})
Convey("should not notify query returns error", func() { Convey("should not notify query returns error", func() {
bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetLatestNotificationQuery) error { bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetNotificationStateQuery) error {
return errors.New("some kind of error unknown error") return errors.New("some kind of error unknown error")
}) })

View File

@ -88,19 +88,6 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
} }
} }
if evalContext.Rule.State == m.AlertStateOK && evalContext.PrevAlertState != m.AlertStateOK {
for _, notifierId := range evalContext.Rule.Notifications {
cmd := &m.CleanNotificationJournalCommand{
AlertId: evalContext.Rule.Id,
NotifierId: notifierId,
OrgId: evalContext.Rule.OrgId,
}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
handler.log.Error("Failed to clean up old notification records", "notifier", notifierId, "alert", evalContext.Rule.Id, "Error", err)
}
}
}
handler.notifier.SendIfNeeded(evalContext) handler.notifier.SendIfNeeded(evalContext)
return nil return nil
} }

View File

@ -20,7 +20,6 @@ func init() {
bus.AddHandler("sql", GetAllAlertNotifications) bus.AddHandler("sql", GetAllAlertNotifications)
bus.AddHandlerCtx("sql", RecordNotificationJournal) bus.AddHandlerCtx("sql", RecordNotificationJournal)
bus.AddHandlerCtx("sql", GetLatestNotification) bus.AddHandlerCtx("sql", GetLatestNotification)
bus.AddHandlerCtx("sql", CleanNotificationJournal)
} }
func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error { func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error {
@ -229,14 +228,13 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
}) })
} }
func RecordNotificationJournal(ctx context.Context, cmd *m.RecordNotificationJournalCommand) error { func RecordNotificationJournal(ctx context.Context, cmd *m.UpdateAlertNotificationStateCommand) error {
return withDbSession(ctx, func(sess *DBSession) error { return withDbSession(ctx, func(sess *DBSession) error {
journalEntry := &m.AlertNotificationJournal{ journalEntry := &m.AlertNotificationState{
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
AlertId: cmd.AlertId, AlertId: cmd.AlertId,
NotifierId: cmd.NotifierId, NotifierId: cmd.NotifierId,
SentAt: cmd.SentAt, SentAt: cmd.SentAt,
Success: cmd.Success,
} }
_, err := sess.Insert(journalEntry) _, err := sess.Insert(journalEntry)
@ -244,9 +242,9 @@ func RecordNotificationJournal(ctx context.Context, cmd *m.RecordNotificationJou
}) })
} }
func GetLatestNotification(ctx context.Context, cmd *m.GetLatestNotificationQuery) error { func GetLatestNotification(ctx context.Context, cmd *m.GetNotificationStateQuery) error {
return withDbSession(ctx, func(sess *DBSession) error { return withDbSession(ctx, func(sess *DBSession) error {
nj := []m.AlertNotificationJournal{} nj := &m.AlertNotificationState{}
err := sess.Desc("alert_notification_journal.sent_at"). err := sess.Desc("alert_notification_journal.sent_at").
Where("alert_notification_journal.org_id = ?", cmd.OrgId). Where("alert_notification_journal.org_id = ?", cmd.OrgId).
@ -262,11 +260,3 @@ func GetLatestNotification(ctx context.Context, cmd *m.GetLatestNotificationQuer
return nil return nil
}) })
} }
func CleanNotificationJournal(ctx context.Context, cmd *m.CleanNotificationJournalCommand) error {
return inTransactionCtx(ctx, func(sess *DBSession) error {
sql := "DELETE FROM alert_notification_journal WHERE alert_notification_journal.org_id = ? AND alert_notification_journal.alert_id = ? AND alert_notification_journal.notifier_id = ?"
_, err := sess.Exec(sql, cmd.OrgId, cmd.AlertId, cmd.NotifierId)
return err
})
}

View File

@ -20,17 +20,17 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
var notifierId int64 = 10 var notifierId int64 = 10
Convey("Getting last journal should raise error if no one exists", func() { Convey("Getting last journal should raise error if no one exists", func() {
query := &m.GetLatestNotificationQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId} query := &m.GetNotificationStateQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId}
GetLatestNotification(context.Background(), query) err := GetLatestNotification(context.Background(), query)
So(len(query.Result), ShouldEqual, 0) So(err, ShouldNotBeNil)
// recording an journal entry in another org to make sure org filter works as expected. // recording an journal entry in another org to make sure org filter works as expected.
journalInOtherOrg := &m.RecordNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: 10, Success: true, SentAt: 1} journalInOtherOrg := &m.UpdateAlertNotificationStateCommand{AlertId: alertId, NotifierId: notifierId, OrgId: 10, SentAt: 1}
err := RecordNotificationJournal(context.Background(), journalInOtherOrg) err = RecordNotificationJournal(context.Background(), journalInOtherOrg)
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("should be able to record two journaling events", func() { Convey("should be able to record two journaling events", func() {
createCmd := &m.RecordNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: orgId, Success: true, SentAt: 1} createCmd := &m.UpdateAlertNotificationStateCommand{AlertId: alertId, NotifierId: notifierId, OrgId: orgId, SentAt: 1}
err := RecordNotificationJournal(context.Background(), createCmd) err := RecordNotificationJournal(context.Background(), createCmd)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -39,27 +39,6 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
err = RecordNotificationJournal(context.Background(), createCmd) err = RecordNotificationJournal(context.Background(), createCmd)
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("get last journaling event", func() {
err := GetLatestNotification(context.Background(), query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2)
last := query.Result[0]
So(last.SentAt, ShouldEqual, 1001)
Convey("be able to clear all journaling for an notifier", func() {
cmd := &m.CleanNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: orgId}
err := CleanNotificationJournal(context.Background(), cmd)
So(err, ShouldBeNil)
Convey("querying for last journaling should return no journal entries", func() {
query := &m.GetLatestNotificationQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId}
err := GetLatestNotification(context.Background(), query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 0)
})
})
})
}) })
}) })
}) })

View File

@ -107,4 +107,25 @@ func addAlertMigrations(mg *Migrator) {
mg.AddMigration("create notification_journal table v1", NewAddTableMigration(notification_journal)) mg.AddMigration("create notification_journal table v1", NewAddTableMigration(notification_journal))
mg.AddMigration("add index notification_journal org_id & alert_id & notifier_id", NewAddIndexMigration(notification_journal, notification_journal.Indices[0])) mg.AddMigration("add index notification_journal org_id & alert_id & notifier_id", NewAddIndexMigration(notification_journal, notification_journal.Indices[0]))
mg.AddMigration("drop alert_notification_journal", NewDropTableMigration("alert_notification_journal"))
alert_notification_state := Table{
Name: "alert_notification_state",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt, Nullable: false},
{Name: "alert_id", Type: DB_BigInt, Nullable: false},
{Name: "notifier_id", Type: DB_BigInt, Nullable: false},
{Name: "sent_at", Type: DB_BigInt, Nullable: false},
{Name: "state", Type: DB_NVarchar, Length: 50, Nullable: false},
{Name: "version", Type: DB_BigInt, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"org_id", "alert_id", "notifier_id"}, Type: IndexType},
},
}
mg.AddMigration("create alert_notification_state table v1", NewAddTableMigration(alert_notification_state))
mg.AddMigration("add index alert_notification_state org_id & alert_id & notifier_id", NewAddIndexMigration(alert_notification_state, notification_journal.Indices[0]))
} }