Skip to content

Commit

Permalink
updater: sleep before continuing the lock loop
Browse files Browse the repository at this point in the history
This change makes the updater sleep for a small portion of time before
it continues to try and obtain a lock for running the updates. This will
prevent the CPU from being pinned in the case where an error is
consistently failing an update.

Fixes #415.
  • Loading branch information
jzelinskie committed Jun 28, 2017
1 parent 04847a0 commit 0d18a62
Showing 1 changed file with 27 additions and 12 deletions.
39 changes: 27 additions & 12 deletions updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ import (
)

const (
updaterLastFlagName = "updater/last"
updaterLockName = "updater"
updaterLockDuration = updaterLockRefreshDuration + time.Minute*2
updaterLockRefreshDuration = time.Minute * 8
updaterLastFlagName = "updater/last"
updaterLockName = "updater"
updaterLockDuration = updaterLockRefreshDuration + time.Minute*2
updaterLockRefreshDuration = time.Minute * 8
updaterSleepBetweenLoopsDuration = time.Minute
)

var (
Expand Down Expand Up @@ -124,7 +125,14 @@ func RunUpdater(config *UpdaterConfig, datastore database.Datastore, st *stopper
if stop {
break
}

// Sleep for a short duration to prevent pinning the CPU on a
// consistent failure.
if stopped := sleepUpdater(time.Now().Add(updaterSleepBetweenLoopsDuration), st); stopped {
break
}
continue

} else {
lockOwner, lockExpiration, err := datastore.FindLock(updaterLockName)
if err != nil {
Expand All @@ -137,14 +145,8 @@ func RunUpdater(config *UpdaterConfig, datastore database.Datastore, st *stopper
}
}

// Sleep, but remain stoppable until approximately the next update time.
now := time.Now().UTC()
waitUntil := nextUpdate.Add(time.Duration(rand.ExpFloat64()/0.5) * time.Second)
log.WithField("scheduled time", waitUntil).Debug("next update attempt scheduled")
if !waitUntil.Before(now) {
if !st.Sleep(waitUntil.Sub(time.Now())) {
break
}
if stopped := sleepUpdater(nextUpdate, st); stopped {
break
}
}

Expand All @@ -159,6 +161,19 @@ func RunUpdater(config *UpdaterConfig, datastore database.Datastore, st *stopper
log.Info("updater service stopped")
}

// sleepUpdater sleeps the updater for an approximate duration, but remains
// able to be cancelled by a stopper.
func sleepUpdater(approxWakeup time.Time, st *stopper.Stopper) (stopped bool) {
waitUntil := approxWakeup.Add(time.Duration(rand.ExpFloat64()/0.5) * time.Second)
log.WithField("scheduled time", waitUntil).Debug("updater sleeping")
if !waitUntil.Before(time.Now().UTC()) {
if !st.Sleep(waitUntil.Sub(time.Now())) {
return true
}
}
return false
}

// update fetches all the vulnerabilities from the registered fetchers, upserts
// them into the database and then sends notifications.
func update(datastore database.Datastore, firstUpdate bool) {
Expand Down

0 comments on commit 0d18a62

Please sign in to comment.