func (b *Backoff) decayN() {
	if b.decay == 0 {
		return
	}
	if b.lastTry.IsZero() {
		b.lastTry = time.Now()
		return
	}
	lastDuration := b.duration(b.n - 1)
	decayed := time.Since(b.lastTry) > lastDuration+b.decay
	b.lastTry = time.Now()
	if !decayed {
		return
	}
	b.n = 0
}
requires b to be locked
package backoff
import (
	"crypto/rand"
	"encoding/binary"
	"io"
	"math"
	mrand "math/rand"
	"sync"
	"time"
)
var prngMu sync.Mutex
var prng *mrand.Rand
var DefaultInterval = 5 * time.Minute
var DefaultMaxDuration = 6 * time.Hour
type Backoff struct {
	maxDuration time.Duration
	interval time.Duration
	noJitter bool
	decay time.Duration
	n       uint64
	lastTry time.Time
}
func New(max time.Duration, interval time.Duration) *Backoff {
	if max < 0 || interval < 0 {
		panic("backoff: max or interval is negative")
	}
	b := &Backoff{
		maxDuration: max,
		interval:    interval,
	}
	b.setup()
	return b
}
func NewWithoutJitter(max time.Duration, interval time.Duration) *Backoff {
	b := New(max, interval)
	b.noJitter = true
	return b
}
func init() {
	var buf [8]byte
	var n int64
	_, err := io.ReadFull(rand.Reader, buf[:])
	if err != nil {
		panic(err.Error())
	}
	n = int64(binary.LittleEndian.Uint64(buf[:]))
	src := mrand.NewSource(n)
	prng = mrand.New(src)
}
func (b *Backoff) setup() {
	if b.interval == 0 {
		b.interval = DefaultInterval
	}
	if b.maxDuration == 0 {
		b.maxDuration = DefaultMaxDuration
	}
}
func (b *Backoff) Duration() time.Duration {
	b.setup()
	b.decayN()
	t := b.duration(b.n)
	if b.n < math.MaxUint64 {
		b.n++
	}
	if !b.noJitter {
		prngMu.Lock()
		t = time.Duration(prng.Int63n(int64(t)))
		prngMu.Unlock()
	}
	return t
}
func (b *Backoff) duration(n uint64) (t time.Duration) {
	pow := time.Duration(math.MaxInt64)
	if n < 63 {
		pow = 1 << n
	}
	t = b.interval * pow
	if t/pow != b.interval || t > b.maxDuration {
		t = b.maxDuration
	}
	return
}
func (b *Backoff) Reset() {
	b.lastTry = time.Time{}
	b.n = 0
}
func (b *Backoff) SetDecay(decay time.Duration) {
	if decay < 0 {
		panic("backoff: decay < 0")
	}
	b.decay = decay
}