Skip to content

Instantly share code, notes, and snippets.

@marselester
Last active August 8, 2022 00:10
Show Gist options
  • Save marselester/b58b11337a09a0defb6466793bef8da0 to your computer and use it in GitHub Desktop.
Save marselester/b58b11337a09a0defb6466793bef8da0 to your computer and use it in GitHub Desktop.
Exponential decorrelated jitter backoff from Polly project based on https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/, see an example https://play.golang.org/p/sHOTAI6wGht.
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func main() {
// Initialize the default source of uniformly-distributed pseudo-random numbers.
rand.Seed(time.Now().UnixNano())
// Make 6 retries with exponential backoff and 1 hour of max wait time between attempts.
// The first delay of 200 seconds is a multiplier that increases the wait intervals.
const (
maxRetries = 6
maxSeconds = 3600.
firstDelaySeconds = 200.
)
retries := backoff(maxRetries, maxSeconds, firstDelaySeconds)
fmt.Println(retries)
}
const (
// pFactor is a factor used within the formula to help smooth the first calculated delay.
pFactor = 4.0
// rpScalingFactor is a factor used to scale the median values of the retry times
// generated by the formula to be near whole seconds, to aid user comprehension.
// This factor allows the median values to fall approximately at 1, 2, 4, ... seconds,
// instead of 1.4, 2.8, 5.6, 11.2.
rpScalingFactor = 1 / 1.4
)
// backoff is the exponential "Decorrelated Jitter" backoff from Polly project
// based on https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/.
// Read more https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry#new-jitter-recommendation and
// https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry/blob/master/src/Polly.Contrib.WaitAndRetry/Backoff.DecorrelatedJitterV2.cs.
func backoff(maxRetries int, maxSeconds, firstDelaySeconds float64) []float64 {
retries := make([]float64, maxRetries)
var prev float64
for i := 0; i < maxRetries; i++ {
t := float64(i) + rand.Float64()
next := math.Pow(2, t) * math.Tanh(math.Sqrt(pFactor*t))
retries[i] = math.Min(
(next-prev)*rpScalingFactor*firstDelaySeconds,
maxSeconds,
)
prev = next
}
return retries
}
@marselester
Copy link
Author

Here is a Go package that does the same thing https://github.com/marselester/backoff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment