Skip to content

Commit

Permalink
notifier: retry upon failure
Browse files Browse the repository at this point in the history
  • Loading branch information
Quentin-M committed Dec 17, 2015
1 parent 3ff8bfa commit 480589a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 8 deletions.
2 changes: 2 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ updater:
# Use 0 to disable the updater entirely.
interval: 2h
notifier:
# How many attempts will the notifier do when a notifier backend fails.
attempts: 3
# Configuration for HTTP notifier
http:
# Endpoint that will receive notifications with POST requests.
Expand Down
6 changes: 5 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ type UpdaterConfig struct {

// NotifierConfig is the configuration for the Notifier service and its registered notifiers.
type NotifierConfig struct {
Params map[string]interface{} `yaml:",inline"`
Attempts int
Params map[string]interface{} `yaml:",inline"`
}

// APIConfig is the configuration for the API service.
Expand All @@ -68,6 +69,9 @@ var DefaultConfig = Config{
HealthPort: 6061,
Timeout: 900 * time.Second,
},
Notifier: &NotifierConfig{
Attempts: 5,
},
}

// Load is a shortcut to open a file, read it, and generate a Config.
Expand Down
38 changes: 31 additions & 7 deletions notifier/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

"github.com/coreos/pkg/capnslog"
"github.com/coreos/pkg/timeutil"
"github.com/pborman/uuid"

"github.com/coreos/clair/config"
Expand All @@ -31,10 +32,10 @@ import (
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "notifier")

const (
checkInterval = 5 * time.Minute

checkInterval = 5 * time.Minute
refreshLockDuration = time.Minute * 2
lockDuration = time.Minute*8 + refreshLockDuration
maxBackOff = 15 * time.Minute
)

// TODO(Quentin-M): Allow registering custom notification handlers.
Expand Down Expand Up @@ -114,7 +115,7 @@ func Run(config *config.NotifierConfig, stopper *utils.Stopper) {
// Handle task.
done := make(chan bool, 1)
go func() {
if handleTask(notification) {
if handleTask(notification, stopper, config.Attempts) {
database.MarkNotificationAsSent(node)
}
database.Unlock(node, whoAmI)
Expand Down Expand Up @@ -160,7 +161,7 @@ func findTask(whoAmI string, stopper *utils.Stopper) (string, database.Notificat
}
}

func handleTask(notification database.Notification) bool {
func handleTask(notification database.Notification, st *utils.Stopper, maxAttempts int) bool {
// Get notification content.
// TODO(Quentin-M): Split big notifications.
notificationContent, err := notification.GetContent()
Expand All @@ -177,11 +178,34 @@ func handleTask(notification database.Notification) bool {
}

// Send notification.
// TODO(Quentin-M): Backoff / MaxRetries
for notifierName, notifier := range notifiers {
if err := notifier.Send(payload); err != nil {
var attempts int
var backOff time.Duration
for {
// Max attempts exceeded.
if attempts >= maxAttempts {
log.Infof("giving up on sending notification '%s' to notifier '%s': max attempts exceeded (%d)\n", notification.GetName(), notifierName, maxAttempts)
return false
}

// Backoff.
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)
if !st.Sleep(backOff) {
return false
}
}

// Send using the current notifier.
if err := notifier.Send(payload); err == nil {
// Send has been successful. Go to the next one.
break
}

// Send failed; increase attempts/backoff and retry.
log.Errorf("could not send notification '%s' to notifier '%s': %s", notification.GetName(), notifierName, err)
return false
backOff = timeutil.ExpBackoff(backOff, maxBackOff)
attempts++
}
}

Expand Down

0 comments on commit 480589a

Please sign in to comment.