From 34204cc40b7c7b272c132f003671b3ee78187b26 Mon Sep 17 00:00:00 2001 From: Jaime Pillora Date: Sat, 28 Feb 2015 17:21:18 +1100 Subject: [PATCH] initial, tests passing --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ backoff.go | 38 +++++++++++++++++++++++++++++ backoff_test.go | 33 ++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 README.md create mode 100644 backoff.go create mode 100644 backoff_test.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca52f05 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# Backoff + +A simple backoff algorithm in Go (Golang) + +# Usage + +Starts at `Min`, multiplied by `Factor` every call to +`Duration()` where it is capped at `Max`. Commonly used +in conjunction with `time.Sleep(duration)`. + +``` go + +b := &backoff.Backoff{ + //These are the defaults + Min: 100 * time.Millisecond, + Max: 10 * time.Second, + Factor: 2, +} + +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 +``` + +#### Credits + +Ported from some JavaScript written by [@tj](https://github.com/tj) + +#### MIT License + +Copyright © 2015 Jaime Pillora <dev@jpillora.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/backoff.go b/backoff.go new file mode 100644 index 0000000..6e42d6d --- /dev/null +++ b/backoff.go @@ -0,0 +1,38 @@ +package backoff + +import ( + "math" + "time" +) + +type Backoff struct { + attempts, Factor int + curr, Min, Max time.Duration +} + +func (b *Backoff) Duration() time.Duration { + //abit hacky though, if zero-value, apply defaults + if b.Min == 0 { + b.Min = 100 * time.Millisecond + } + if b.Max == 0 { + b.Max = 10 * time.Second + } + if b.Factor == 0 { + b.Factor = 2 + } + if b.curr == 0 { + b.curr = b.Min + } + + //calculate next duration in ms + ms := float64(b.curr) * math.Pow(float64(b.Factor), float64(b.attempts)) + //bump attempts count + b.attempts++ + //return as a time.Duration + return time.Duration(math.Min(ms, float64(b.Max))) +} + +func (b *Backoff) Reset() { + b.attempts = 0 +} diff --git a/backoff_test.go b/backoff_test.go new file mode 100644 index 0000000..d68dd41 --- /dev/null +++ b/backoff_test.go @@ -0,0 +1,33 @@ +package backoff + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + + b := &Backoff{ + Min: 100 * time.Millisecond, + Max: 10 * time.Second, + Factor: 2, + } + + if b.Duration() != 100*time.Millisecond { + t.Error("Should be 100ms") + } + + if b.Duration() != 200*time.Millisecond { + t.Error("Should be 200ms") + } + + if b.Duration() != 400*time.Millisecond { + t.Error("Should be 400ms") + } + + b.Reset() + + if b.Duration() != 100*time.Millisecond { + t.Error("Should be 100ms again") + } +}