AlertNotifications: Translate notifications IDs to UIDs in Rule builder (#19882)
* AlertNotifications: Translate notifications IDs to UIDs in alert Rule builder * Avoid shadowing errors, raise validation error on non-existing notification id * create a cache for notification Uids to minimize db overhead * add cache usage test * avoid caching empty notification Uids * isolate db in alert notificationUid caching tests
This commit is contained in:
@@ -67,6 +67,32 @@ func GetAlertNotifications(query *models.GetAlertNotificationsQuery) error {
|
||||
return getAlertNotificationInternal(query, newSession())
|
||||
}
|
||||
|
||||
func (ss *SqlStore) addAlertNotificationUidByIdHandler() {
|
||||
bus.AddHandler("sql", ss.GetAlertNotificationUidWithId)
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetAlertNotificationUidWithId(query *models.GetAlertNotificationUidQuery) error {
|
||||
cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id)
|
||||
|
||||
if cached, found := ss.CacheService.Get(cacheKey); found {
|
||||
query.Result = cached.(string)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := getAlertNotificationUidInternal(query, newSession())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ss.CacheService.Set(cacheKey, query.Result, -1) //Infinite, never changes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newAlertNotificationUidCacheKey(orgID, notificationId int64) string {
|
||||
return fmt.Sprintf("notification-uid-by-org-%d-and-id-%d", orgID, notificationId)
|
||||
}
|
||||
|
||||
func GetAlertNotificationsWithUid(query *models.GetAlertNotificationsWithUidQuery) error {
|
||||
return getAlertNotificationWithUidInternal(query, newSession())
|
||||
}
|
||||
@@ -124,6 +150,35 @@ func GetAlertNotificationsWithUidToSend(query *models.GetAlertNotificationsWithU
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAlertNotificationUidInternal(query *models.GetAlertNotificationUidQuery, sess *DBSession) error {
|
||||
var sql bytes.Buffer
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
sql.WriteString(`SELECT
|
||||
alert_notification.uid
|
||||
FROM alert_notification
|
||||
`)
|
||||
|
||||
sql.WriteString(` WHERE alert_notification.org_id = ?`)
|
||||
params = append(params, query.OrgId)
|
||||
|
||||
sql.WriteString(` AND alert_notification.id = ?`)
|
||||
params = append(params, query.Id)
|
||||
|
||||
results := make([]string, 0)
|
||||
if err := sess.SQL(sql.String(), params...).Find(&results); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
return fmt.Errorf("Alert notification [ Id: %v, OrgId: %v ] not found", query.Id, query.OrgId)
|
||||
}
|
||||
|
||||
query.Result = results[0]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAlertNotificationInternal(query *models.GetAlertNotificationsQuery, sess *DBSession) error {
|
||||
var sql bytes.Buffer
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
@@ -321,5 +321,71 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Notification Uid by Id Caching", func() {
|
||||
ss := InitTestDB(t)
|
||||
|
||||
notification := &models.CreateAlertNotificationCommand{Uid: "aNotificationUid", OrgId: 1, Name: "aNotificationUid"}
|
||||
err := CreateAlertNotificationCommand(notification)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
byUidQuery := &models.GetAlertNotificationsWithUidQuery{
|
||||
Uid: notification.Uid,
|
||||
OrgId: notification.OrgId,
|
||||
}
|
||||
|
||||
notificationByUidErr := GetAlertNotificationsWithUid(byUidQuery)
|
||||
So(notificationByUidErr, ShouldBeNil)
|
||||
|
||||
Convey("Can cache notification Uid", func() {
|
||||
byIdQuery := &models.GetAlertNotificationUidQuery{
|
||||
Id: byUidQuery.Result.Id,
|
||||
OrgId: byUidQuery.Result.OrgId,
|
||||
}
|
||||
|
||||
cacheKey := newAlertNotificationUidCacheKey(byIdQuery.OrgId, byIdQuery.Id)
|
||||
|
||||
resultBeforeCaching, foundBeforeCaching := ss.CacheService.Get(cacheKey)
|
||||
So(foundBeforeCaching, ShouldBeFalse)
|
||||
So(resultBeforeCaching, ShouldBeNil)
|
||||
|
||||
notificationByIdErr := ss.GetAlertNotificationUidWithId(byIdQuery)
|
||||
So(notificationByIdErr, ShouldBeNil)
|
||||
|
||||
resultAfterCaching, foundAfterCaching := ss.CacheService.Get(cacheKey)
|
||||
So(foundAfterCaching, ShouldBeTrue)
|
||||
So(resultAfterCaching, ShouldEqual, notification.Uid)
|
||||
})
|
||||
|
||||
Convey("Retrieves from cache when exists", func() {
|
||||
query := &models.GetAlertNotificationUidQuery{
|
||||
Id: 999,
|
||||
OrgId: 100,
|
||||
}
|
||||
cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id)
|
||||
ss.CacheService.Set(cacheKey, "a-cached-uid", -1)
|
||||
|
||||
err := ss.GetAlertNotificationUidWithId(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result, ShouldEqual, "a-cached-uid")
|
||||
})
|
||||
|
||||
Convey("Returns an error without populating cache when the notification doesn't exist in the database", func() {
|
||||
query := &models.GetAlertNotificationUidQuery{
|
||||
Id: -1,
|
||||
OrgId: 100,
|
||||
}
|
||||
|
||||
err := ss.GetAlertNotificationUidWithId(query)
|
||||
So(query.Result, ShouldEqual, "")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(err.Error(), ShouldEqual, "Alert notification [ Id: -1, OrgId: 100 ] not found")
|
||||
|
||||
cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id)
|
||||
result, found := ss.CacheService.Get(cacheKey)
|
||||
So(found, ShouldBeFalse)
|
||||
So(result, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ func (ss *SqlStore) Init() error {
|
||||
|
||||
// Register handlers
|
||||
ss.addUserQueryAndCommandHandlers()
|
||||
ss.addAlertNotificationUidByIdHandler()
|
||||
|
||||
if ss.skipEnsureDefaultOrgAndUser {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user