notifier: fix a bug that prevented graceful shutdown in certain cases

- The notifier was never checking if it should shutdown if there were always at least one notification to send
- After a failure, the notifier is supposed to back-off, but when Clair is stopping, the backoff was interrupted immediately and did not retry. Instead it selected a new notification to send (most likely: the same one) and looped quickly/weirdly.
This commit is contained in:
Quentin Machu 2015-12-15 13:23:57 -05:00
parent 480589a83a
commit 2ea86c53f3

View File

@ -104,20 +104,25 @@ func Run(config *config.NotifierConfig, stopper *utils.Stopper) {
// Register healthchecker. // Register healthchecker.
health.RegisterHealthchecker("notifier", Healthcheck) health.RegisterHealthchecker("notifier", Healthcheck)
for { for running := true; running; {
// Find task. // Find task.
// TODO(Quentin-M): Combine node and notification. // TODO(Quentin-M): Combine node and notification.
node, notification := findTask(whoAmI, stopper) node, notification := findTask(whoAmI, stopper)
if node == "" && notification == nil { if node == "" && notification == nil {
// Interrupted while finding a task, Clair is stopping.
break break
} }
// Handle task. // Handle task.
done := make(chan bool, 1) done := make(chan bool, 1)
go func() { go func() {
if handleTask(notification, stopper, config.Attempts) { success, interrupted := handleTask(notification, stopper, config.Attempts)
if success {
database.MarkNotificationAsSent(node) database.MarkNotificationAsSent(node)
} }
if interrupted {
running = false
}
database.Unlock(node, whoAmI) database.Unlock(node, whoAmI)
done <- true done <- true
}() }()
@ -161,13 +166,13 @@ func findTask(whoAmI string, stopper *utils.Stopper) (string, database.Notificat
} }
} }
func handleTask(notification database.Notification, st *utils.Stopper, maxAttempts int) bool { func handleTask(notification database.Notification, st *utils.Stopper, maxAttempts int) (bool, bool) {
// Get notification content. // Get notification content.
// TODO(Quentin-M): Split big notifications. // TODO(Quentin-M): Split big notifications.
notificationContent, err := notification.GetContent() notificationContent, err := notification.GetContent()
if err != nil { if err != nil {
log.Warningf("could not get content of notification '%s': %s", notification.GetName(), err) log.Warningf("could not get content of notification '%s': %s", notification.GetName(), err)
return false return false, false
} }
// Create notification. // Create notification.
@ -185,14 +190,14 @@ func handleTask(notification database.Notification, st *utils.Stopper, maxAttemp
// Max attempts exceeded. // Max attempts exceeded.
if attempts >= maxAttempts { if attempts >= maxAttempts {
log.Infof("giving up on sending notification '%s' to notifier '%s': max attempts exceeded (%d)\n", notification.GetName(), notifierName, maxAttempts) log.Infof("giving up on sending notification '%s' to notifier '%s': max attempts exceeded (%d)\n", notification.GetName(), notifierName, maxAttempts)
return false return false, false
} }
// Backoff. // Backoff.
if backOff > 0 { if backOff > 0 {
log.Infof("waiting %v before retrying to send notification '%s' to notifier '%s' (Attempt %d / %d)\n", backOff, notification.GetName(), notifierName, attempts+1, maxAttempts) log.Infof("waiting %v before retrying to send notification '%s' to notifier '%s' (Attempt %d / %d)\n", backOff, notification.GetName(), notifierName, attempts+1, maxAttempts)
if !st.Sleep(backOff) { if !st.Sleep(backOff) {
return false return false, true
} }
} }
@ -210,7 +215,7 @@ func handleTask(notification database.Notification, st *utils.Stopper, maxAttemp
} }
log.Infof("successfully sent notification '%s'\n", notification.GetName()) log.Infof("successfully sent notification '%s'\n", notification.GetName())
return true return true, false
} }
// Healthcheck returns the health of the notifier service. // Healthcheck returns the health of the notifier service.