A simple exponential backoff counter in Go (Golang)
$ go get -v github.com/jpillora/backoff
Backoff is a time.Duration
counter. It starts at Min
. After every call to Duration()
it is multiplied by Factor
. It is capped at Max
. It returns to Min
on every call to Reset()
. Jitter
adds randomness (see below). Used in conjunction with the time
package.
b := &backoff.Backoff{ //These are the defaults Min: 100 * time.Millisecond, Max: 10 * time.Second, Factor: 2, Jitter: false, } fmt.Printf("%s\n", b.Duration()) fmt.Printf("%s\n", b.Duration()) fmt.Printf("%s\n", b.Duration()) fmt.Printf("Reset!\n") b.Reset() fmt.Printf("%s\n", b.Duration())
100ms 200ms 400ms Reset! 100ms
net
packageb := &backoff.Backoff{ Max: 5 * time.Minute, } for { conn, err := net.Dial("tcp", "example.com:5309") if err != nil { d := b.Duration() fmt.Printf("%s, reconnecting in %s", err, d) time.Sleep(d) continue } //connected b.Reset() conn.Write([]byte("hello world!")) // ... Read ... Write ... etc conn.Close() //disconnected }
Jitter
Enabling Jitter
adds some randomization to the backoff durations. See Amazon's writeup of performance gains using jitter. Seeding is not necessary but doing so gives repeatable results.
import "math/rand"
b := &backoff.Backoff{
Jitter: true,
}
rand.Seed(42)
fmt.Printf("%s\n", b.Duration())
fmt.Printf("%s\n", b.Duration())
fmt.Printf("%s\n", b.Duration())
fmt.Printf("Reset!\n")
b.Reset()
fmt.Printf("%s\n", b.Duration())
fmt.Printf("%s\n", b.Duration())
fmt.Printf("%s\n", b.Duration())
100ms 106.600049ms 281.228155ms Reset! 100ms 104.381845ms 214.957989ms
https://godoc.org/github.com/jpillora/backoff
Forked from some JavaScript written by @tj