in swim/join_delayer.go [144:191]
func (d *exponentialDelayer) delay() time.Duration {
// Convert durations to time in millis
initialDelayMs := float64(util.MS(d.initialDelay))
maxDelayMs := float64(util.MS(d.maxDelay))
// Compute uncapped exponential delay (exponent is the number of join
// attempts so far). Then, make sure the computed delay is capped at its
// max. Apply a random jitter to the actual sleep duration and finally,
// sleep.
uncappedDelay := initialDelayMs * math.Pow(2, float64(d.numDelays))
cappedDelay := math.Min(maxDelayMs, uncappedDelay)
// If cappedDelay and nextDelayMin are equal, we have reached the point
// at which the exponential backoff has reached its max; apply no more
// jitter.
var jitteredDelay int
if cappedDelay == d.nextDelayMin {
jitteredDelay = int(cappedDelay)
} else {
jitteredDelay = d.randomizer(int(cappedDelay-d.nextDelayMin)) + int(d.nextDelayMin)
}
// If this is the first time an uncapped delay reached or exceeded the
// maximum allowable delay, log a message.
if uncappedDelay >= maxDelayMs && d.maxDelayReached == false {
d.logger.WithFields(bark.Fields{
"numDelays": d.numDelays,
"initialDelay": d.initialDelay,
"minDelay": d.nextDelayMin,
"maxDelay": d.maxDelay,
"uncappedDelay": uncappedDelay,
"cappedDelay": cappedDelay,
"jitteredDelay": jitteredDelay,
}).Warn("ringpop join attempt delay reached max")
d.maxDelayReached = true
}
// Set lower-bound for next attempt to maximum of current attempt.
d.nextDelayMin = cappedDelay
sleepDuration := time.Duration(jitteredDelay) * time.Millisecond
d.sleeper(sleepDuration)
// Increment the exponent used for backoff calculation.
d.numDelays++
return sleepDuration
}