mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
pkg/util: rm retry
This commit is contained in:
parent
87d763598f
commit
dbac45aa76
|
@ -1,69 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
InfiniteRetry = 0
|
||||
)
|
||||
|
||||
type RetryPredicator func(e error) bool
|
||||
|
||||
// Retry retrys the passed function for "attempts" times, if passed function return error. Setting attempts to zero means keep retrying.
|
||||
func Retry(ctx context.Context, attempts int, duration time.Duration, fnToRetry func() error, errHandler func(error), predicators ...RetryPredicator) (err error) {
|
||||
infinite := false
|
||||
if attempts == InfiniteRetry {
|
||||
infinite = true
|
||||
}
|
||||
|
||||
for attempts > 0 || infinite {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errMsg := "return for context done"
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMsg)
|
||||
} else {
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
default:
|
||||
if err = fnToRetry(); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !needRetry(err, predicators) {
|
||||
return err
|
||||
}
|
||||
|
||||
err = errors.Wrapf(err, "failed in retry: countdown: %v", attempts)
|
||||
|
||||
if errHandler != nil {
|
||||
errHandler(err)
|
||||
}
|
||||
|
||||
if !infinite {
|
||||
attempts--
|
||||
}
|
||||
|
||||
time.Sleep(duration)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func needRetry(err error, predicators []RetryPredicator) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// If no predicators specified, we will retry for all errors
|
||||
if len(predicators) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return predicators[0](err)
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func addAndCheck(a *int, target int) error {
|
||||
if *a++; *a == target {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("a is not %v. It is %v\n", target, *a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetry(t *testing.T) {
|
||||
type test struct {
|
||||
input int
|
||||
targetNum int
|
||||
ans int
|
||||
ansErr error
|
||||
}
|
||||
tests := []test{
|
||||
{input: 0, targetNum: 3, ans: 3, ansErr: nil},
|
||||
{input: 0, targetNum: 10, ans: 3, ansErr: errors.New("failed in retry")},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
errHandled := false
|
||||
|
||||
err := Retry(context.Background(), 3, 1*time.Second, func() error {
|
||||
return addAndCheck(&tc.input, tc.targetNum)
|
||||
}, func(e error) { errHandled = true })
|
||||
|
||||
assert.Equal(t, true, errHandled)
|
||||
if tc.ansErr == nil {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Contains(t, err.Error(), tc.ansErr.Error())
|
||||
}
|
||||
assert.Equal(t, tc.ans, tc.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryWithPredicator(t *testing.T) {
|
||||
type test struct {
|
||||
count int
|
||||
f func() error
|
||||
errHandler func(error)
|
||||
predicator RetryPredicator
|
||||
ansCount int
|
||||
ansErr error
|
||||
}
|
||||
knownErr := errors.New("Duplicate entry '1-389837488-1' for key 'UNI_Trade'")
|
||||
unknownErr := errors.New("Some Error")
|
||||
tests := []test{
|
||||
{
|
||||
predicator: func(err error) bool {
|
||||
return !strings.Contains(err.Error(), "Duplicate entry")
|
||||
},
|
||||
f: func() error { return knownErr },
|
||||
ansCount: 1,
|
||||
ansErr: knownErr,
|
||||
},
|
||||
{
|
||||
predicator: func(err error) bool {
|
||||
return !strings.Contains(err.Error(), "Duplicate entry")
|
||||
},
|
||||
f: func() error { return unknownErr },
|
||||
ansCount: 3,
|
||||
ansErr: unknownErr,
|
||||
},
|
||||
}
|
||||
attempts := 3
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
for _, tc := range tests {
|
||||
err := Retry(ctx, attempts, 100*time.Millisecond, func() error {
|
||||
tc.count++
|
||||
return tc.f()
|
||||
}, tc.errHandler, tc.predicator)
|
||||
|
||||
assert.Equal(t, tc.ansCount, tc.count)
|
||||
assert.EqualError(t, errors.Cause(err), tc.ansErr.Error(), "should be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryCtxCancel(t *testing.T) {
|
||||
result := int(0)
|
||||
target := int(3)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
err := Retry(ctx, 5, 1*time.Second, func() error { return addAndCheck(&result, target) }, func(error) {})
|
||||
assert.Error(t, err)
|
||||
fmt.Println("Error:", err.Error())
|
||||
assert.Equal(t, int(0), result)
|
||||
}
|
Loading…
Reference in New Issue
Block a user