diff --git a/client/client.go b/client/client.go index 414ea29..a907954 100644 --- a/client/client.go +++ b/client/client.go @@ -12,7 +12,7 @@ import ( "net/http" "time" - backoff "github.com/cloudflare/cfssl/transport/core" + "github.com/cloudflare/backoff" "github.com/cloudflare/redoctober/core" ) diff --git a/vendor/github.com/cloudflare/backoff/LICENSE b/vendor/github.com/cloudflare/backoff/LICENSE new file mode 100644 index 0000000..965145f --- /dev/null +++ b/vendor/github.com/cloudflare/backoff/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2016 CloudFlare Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/cloudflare/backoff/backoff.go b/vendor/github.com/cloudflare/backoff/backoff.go new file mode 100644 index 0000000..ee054e1 --- /dev/null +++ b/vendor/github.com/cloudflare/backoff/backoff.go @@ -0,0 +1,197 @@ +// Package backoff contains an implementation of an intelligent backoff +// strategy. It is based on the approach in the AWS architecture blog +// article titled "Exponential Backoff And Jitter", which is found at +// http://www.awsarchitectureblog.com/2015/03/backoff.html. +// +// Essentially, the backoff has an interval `time.Duration`; the nth +// call to backoff will return a `time.Duration` that is 2^n * +// interval. If jitter is enabled (which is the default behaviour), +// the duration is a random value between 0 and 2^n * interval. The +// backoff is configured with a maximum duration that will not be +// exceeded. +// +// The `New` function will attempt to use the system's cryptographic +// random number generator to seed a Go math/rand random number +// source. If this fails, the package will panic on startup. +package backoff + +import ( + "crypto/rand" + "encoding/binary" + "io" + "math" + mrand "math/rand" + "sync" + "time" +) + +var prngMu sync.Mutex +var prng *mrand.Rand + +// DefaultInterval is used when a Backoff is initialised with a +// zero-value Interval. +var DefaultInterval = 5 * time.Minute + +// DefaultMaxDuration is maximum amount of time that the backoff will +// delay for. +var DefaultMaxDuration = 6 * time.Hour + +// A Backoff contains the information needed to intelligently backoff +// and retry operations using an exponential backoff algorithm. It should +// be initialised with a call to `New`. +// +// Only use a Backoff from a single goroutine, it is not safe for concurrent +// access. +type Backoff struct { + // maxDuration is the largest possible duration that can be + // returned from a call to Duration. + maxDuration time.Duration + + // interval controls the time step for backing off. + interval time.Duration + + // noJitter controls whether to use the "Full Jitter" + // improvement to attempt to smooth out spikes in a high + // contention scenario. If noJitter is set to true, no + // jitter will be introduced. + noJitter bool + + // decay controls the decay of n. If it is non-zero, n is + // reset if more than the last backoff + decay has elapsed since + // the last try. + decay time.Duration + + n uint64 + lastTry time.Time +} + +// New creates a new backoff with the specified max duration and +// interval. Zero values may be used to use the default values. +// +// Panics if either max or interval is negative. +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 +} + +// NewWithoutJitter works similarly to New, except that the created +// Backoff will not use jitter. +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 + } +} + +// Duration returns a time.Duration appropriate for the backoff, +// incrementing the attempt counter. +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 +} + +// requires b to be locked. +func (b *Backoff) duration(n uint64) (t time.Duration) { + // Saturate pow + 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 +} + +// Reset resets the attempt counter of a backoff. +// +// It should be called when the rate-limited action succeeds. +func (b *Backoff) Reset() { + b.lastTry = time.Time{} + b.n = 0 +} + +// SetDecay sets the duration after which the try counter will be reset. +// Panics if decay is smaller than 0. +// +// The decay only kicks in if at least the last backoff + decay has elapsed +// since the last try. +func (b *Backoff) SetDecay(decay time.Duration) { + if decay < 0 { + panic("backoff: decay < 0") + } + + b.decay = decay +} + +// requires b to be locked +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 +} diff --git a/vendor/manifest b/vendor/manifest index 42ad850..780ff08 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -10,6 +10,14 @@ "path": "/quantile", "notests": true }, + { + "importpath": "github.com/cloudflare/backoff", + "repository": "https://github.com/cloudflare/backoff", + "vcs": "git", + "revision": "f659644c644c7ac3564c8acba556d8d74a07c547", + "branch": "master", + "notests": true + }, { "importpath": "github.com/coreos/go-systemd/activation", "repository": "https://github.com/coreos/go-systemd",