Commit c5278af6 by bergquist

add support for mysql and postgres unique index error codes

parent 3fab6162
...@@ -11,7 +11,7 @@ var ( ...@@ -11,7 +11,7 @@ var (
ErrNotificationFrequencyNotFound = errors.New("Notification frequency not specified") ErrNotificationFrequencyNotFound = errors.New("Notification frequency not specified")
ErrAlertNotificationStateNotFound = errors.New("alert notification state not found") ErrAlertNotificationStateNotFound = errors.New("alert notification state not found")
ErrAlertNotificationStateVersionConflict = errors.New("alert notification state update version conflict") ErrAlertNotificationStateVersionConflict = errors.New("alert notification state update version conflict")
ErrAlertNotificationStateAllreadyExist = errors.New("alert notification state allready exists.") ErrAlertNotificationStateAlreadyExist = errors.New("alert notification state already exists.")
) )
type AlertNotificationStateType string type AlertNotificationStateType string
...@@ -95,13 +95,17 @@ type AlertNotificationState struct { ...@@ -95,13 +95,17 @@ type AlertNotificationState struct {
Version int64 Version int64
} }
type UpdateAlertNotificationStateCommand struct { type SetAlertNotificationStateToPendingCommand struct {
Id int64 Id int64
SentAt int64 SentAt int64
State AlertNotificationStateType
Version int64 Version int64
} }
type SetAlertNotificationStateToCompleteCommand struct {
Id int64
SentAt int64
}
type GetNotificationStateQuery struct { type GetNotificationStateQuery struct {
OrgId int64 OrgId int64
AlertId int64 AlertId int64
......
...@@ -64,6 +64,8 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi ...@@ -64,6 +64,8 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi
err := bus.InTransaction(evalContext.Ctx, func(ctx context.Context) error { err := bus.InTransaction(evalContext.Ctx, func(ctx context.Context) error {
n.log.Debug("trying to send notification", "id", not.GetNotifierId()) n.log.Debug("trying to send notification", "id", not.GetNotifierId())
// insert if needed
// 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) {
......
...@@ -20,6 +20,8 @@ func init() { ...@@ -20,6 +20,8 @@ func init() {
bus.AddHandler("sql", GetAllAlertNotifications) bus.AddHandler("sql", GetAllAlertNotifications)
bus.AddHandlerCtx("sql", InsertAlertNotificationState) bus.AddHandlerCtx("sql", InsertAlertNotificationState)
bus.AddHandlerCtx("sql", GetAlertNotificationState) bus.AddHandlerCtx("sql", GetAlertNotificationState)
bus.AddHandlerCtx("sql", SetAlertNotificationStateToCompleteCommand)
bus.AddHandlerCtx("sql", SetAlertNotificationStateToPendingCommand)
} }
func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error { func DeleteAlertNotification(cmd *m.DeleteAlertNotificationCommand) error {
...@@ -244,25 +246,54 @@ func InsertAlertNotificationState(ctx context.Context, cmd *m.InsertAlertNotific ...@@ -244,25 +246,54 @@ func InsertAlertNotificationState(ctx context.Context, cmd *m.InsertAlertNotific
return nil return nil
} }
if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") { uniqenessIndexFailureCodes := []string{
return m.ErrAlertNotificationStateAllreadyExist "UNIQUE constraint failed",
"pq: duplicate key value violates unique constraint",
"Error 1062: Duplicate entry ",
}
for _, code := range uniqenessIndexFailureCodes {
if strings.HasPrefix(err.Error(), code) {
return m.ErrAlertNotificationStateAlreadyExist
}
} }
return err return err
}) })
} }
func UpdateAlertNotificationState(ctx context.Context, cmd *m.UpdateAlertNotificationStateCommand) error { func SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *m.SetAlertNotificationStateToCompleteCommand) error {
return withDbSession(ctx, func(sess *DBSession) error {
sql := `UPDATE alert_notification_state SET
state= ?
WHERE
id = ?`
res, err := sess.Exec(sql, m.AlertNotificationStateCompleted, cmd.Id)
if err != nil {
return err
}
affected, _ := res.RowsAffected()
if affected == 0 {
return m.ErrAlertNotificationStateVersionConflict
}
return nil
})
}
func SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *m.SetAlertNotificationStateToPendingCommand) error {
return withDbSession(ctx, func(sess *DBSession) error { return withDbSession(ctx, func(sess *DBSession) error {
sql := `UPDATE alert_notification_state SET sql := `UPDATE alert_notification_state SET
state= ?, state= ?,
version = ? version = ?
WHERE WHERE
id = ? AND id = ? AND
version = ? version = ?`
`
res, err := sess.Exec(sql, cmd.State, cmd.Version+1, cmd.Id, cmd.Version) res, err := sess.Exec(sql, m.AlertNotificationStatePending, cmd.Version+1, cmd.Id, cmd.Version)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -38,23 +38,28 @@ func TestAlertNotificationSQLAccess(t *testing.T) { ...@@ -38,23 +38,28 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = InsertAlertNotificationState(context.Background(), createCmd) err = InsertAlertNotificationState(context.Background(), createCmd)
So(err, ShouldEqual, models.ErrAlertNotificationStateAllreadyExist) So(err, ShouldEqual, models.ErrAlertNotificationStateAlreadyExist)
Convey("should be able to update alert notifier state", func() { Convey("should be able to update alert notifier state", func() {
updateCmd := &models.UpdateAlertNotificationStateCommand{ updateCmd := &models.SetAlertNotificationStateToPendingCommand{
Id: 1, Id: 1,
SentAt: 1, SentAt: 1,
State: models.AlertNotificationStatePending,
Version: 0, Version: 0,
} }
err := UpdateAlertNotificationState(context.Background(), updateCmd) err := SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd)
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("should not be able to update older versions", func() { Convey("should not be able to set pending on old version", func() {
err = UpdateAlertNotificationState(context.Background(), updateCmd) err = SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd)
So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict) So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict)
}) })
Convey("should be able to set state to completed", func() {
cmd := &models.SetAlertNotificationStateToCompleteCommand{Id: 1}
err = SetAlertNotificationStateToCompleteCommand(context.Background(), cmd)
So(err, ShouldBeNil)
})
}) })
}) })
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment