-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #73 from mailgun/thrawn/develop
Added setter.IsNil and retry package
- Loading branch information
Showing
10 changed files
with
723 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package collections_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/mailgun/holster/v3/collections" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewExpireCache(t *testing.T) { | ||
ec := collections.NewExpireCache(time.Millisecond * 100) | ||
|
||
ec.Add("one", "one") | ||
time.Sleep(time.Millisecond * 100) | ||
|
||
var runs int | ||
ec.Each(1, func(key interface{}, value interface{}) error { | ||
assert.Equal(t, key, "one") | ||
assert.Equal(t, value, "one") | ||
runs++ | ||
return nil | ||
}) | ||
assert.Equal(t, runs, 1) | ||
|
||
// Should NOT be in the cache | ||
time.Sleep(time.Millisecond * 100) | ||
ec.Each(1, func(key interface{}, value interface{}) error { | ||
runs++ | ||
return nil | ||
}) | ||
assert.Equal(t, runs, 1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// +build go1.13 | ||
|
||
package errors | ||
|
||
import ( | ||
stderrors "errors" | ||
) | ||
|
||
// Is reports whether any error in err's chain matches target. | ||
// | ||
// The chain consists of err itself followed by the sequence of errors obtained by | ||
// repeatedly calling Unwrap. | ||
// | ||
// An error is considered to match a target if it is equal to that target or if | ||
// it implements a method Is(error) bool such that Is(target) returns true. | ||
func Is(err, target error) bool { return stderrors.Is(err, target) } | ||
|
||
// As finds the first error in err's chain that matches target, and if so, sets | ||
// target to that error value and returns true. | ||
// | ||
// The chain consists of err itself followed by the sequence of errors obtained by | ||
// repeatedly calling Unwrap. | ||
// | ||
// An error matches target if the error's concrete value is assignable to the value | ||
// pointed to by target, or if the error has a method As(interface{}) bool such that | ||
// As(target) returns true. In the latter case, the As method is responsible for | ||
// setting target. | ||
// | ||
// As will panic if target is not a non-nil pointer to either a type that implements | ||
// error, or to any interface type. As returns false if err is nil. | ||
func As(err error, target interface{}) bool { return stderrors.As(err, target) } | ||
|
||
// Unwrap returns the result of calling the Unwrap method on err, if err's | ||
// type contains an Unwrap method returning error. | ||
// Otherwise, Unwrap returns nil. | ||
func Unwrap(err error) error { | ||
return stderrors.Unwrap(err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package retry | ||
|
||
import ( | ||
"math" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
type BackOff interface { | ||
New() BackOff | ||
Next() (time.Duration, bool) | ||
NumRetries() int | ||
Reset() | ||
} | ||
|
||
func Interval(t time.Duration) *ConstBackOff { | ||
return &ConstBackOff{Interval: t} | ||
} | ||
|
||
// Retry indefinitely sleeping for `interval` between each retry | ||
type ConstBackOff struct { | ||
Interval time.Duration | ||
retries int64 | ||
} | ||
|
||
func (b *ConstBackOff) NumRetries() int { return int(atomic.LoadInt64(&b.retries)) } | ||
func (b *ConstBackOff) Reset() {} | ||
func (b *ConstBackOff) Next() (time.Duration, bool) { | ||
atomic.AddInt64(&b.retries, 1) | ||
return b.Interval, true | ||
} | ||
func (b *ConstBackOff) New() BackOff { | ||
return &ConstBackOff{ | ||
retries: atomic.LoadInt64(&b.retries), | ||
Interval: b.Interval, | ||
} | ||
} | ||
|
||
func Attempts(a int, t time.Duration) *AttemptsBackOff { | ||
return &AttemptsBackOff{Interval: t, Attempts: int64(a)} | ||
} | ||
|
||
// Retry for `attempts` number of retries sleeping for `interval` between each retry | ||
type AttemptsBackOff struct { | ||
Interval time.Duration | ||
Attempts int64 | ||
retries int64 | ||
} | ||
|
||
func (b *AttemptsBackOff) NumRetries() int { return int(atomic.LoadInt64(&b.retries)) } | ||
func (b *AttemptsBackOff) Reset() { atomic.StoreInt64(&b.retries, 0) } | ||
func (b *AttemptsBackOff) Next() (time.Duration, bool) { | ||
retries := atomic.AddInt64(&b.retries, 1) | ||
if retries < b.Attempts { | ||
return b.Interval, true | ||
} | ||
return b.Interval, false | ||
} | ||
func (b *AttemptsBackOff) New() BackOff { | ||
return &AttemptsBackOff{ | ||
retries: atomic.LoadInt64(&b.retries), | ||
Interval: b.Interval, | ||
Attempts: b.Attempts, | ||
} | ||
} | ||
|
||
type ExponentialBackOff struct { | ||
Min, Max time.Duration | ||
Factor float64 | ||
Attempts int64 | ||
retries int64 | ||
} | ||
|
||
func (b *ExponentialBackOff) NumRetries() int { return int(atomic.LoadInt64(&b.retries)) } | ||
func (b *ExponentialBackOff) Reset() { atomic.StoreInt64(&b.retries, 0) } | ||
func (b *ExponentialBackOff) Next() (time.Duration, bool) { | ||
retries := atomic.AddInt64(&b.retries, 1) | ||
interval := b.nextInterval(retries) | ||
if b.Attempts != 0 && retries > b.Attempts { | ||
return interval, false | ||
} | ||
return interval, true | ||
} | ||
func (b *ExponentialBackOff) New() BackOff { | ||
return &ExponentialBackOff{ | ||
retries: atomic.LoadInt64(&b.retries), | ||
Attempts: b.Attempts, | ||
Factor: b.Factor, | ||
Min: b.Min, | ||
Max: b.Max, | ||
} | ||
} | ||
|
||
func (b *ExponentialBackOff) nextInterval(retries int64) time.Duration { | ||
d := time.Duration(float64(b.Min) * math.Pow(b.Factor, float64(retries))) | ||
if d > b.Max { | ||
return b.Max | ||
} | ||
if d < b.Min { | ||
return b.Min | ||
} | ||
return d | ||
} |
Oops, something went wrong.