Codebase list golang-gopkg-eapache-go-resiliency.v1 / 842e16e
Merge pull request #20 from tukeJonny/retrier-runctx Add RunCtx to retrier Evan Huus authored 5 years ago GitHub committed 5 years ago
3 changed file(s) with 67 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
00 language: go
11
22 go:
3 - 1.2
4 - 1.6
5 - 1.10
3 - 1.7
4 - "1.10"
11 package retrier
22
33 import (
4 "context"
45 "math/rand"
56 "sync"
67 "time"
3233 }
3334 }
3435
35 // Run executes the given work function, then classifies its return value based on the classifier used
36 // Run executes the given work function by executing RunCtx without context.Context.
37 func (r *Retrier) Run(work func() error) error {
38 return r.RunCtx(context.Background(), func(ctx context.Context) error {
39 // never use ctx
40 return work()
41 })
42 }
43
44 // RunCtx executes the given work function, then classifies its return value based on the classifier used
3645 // to construct the Retrier. If the result is Succeed or Fail, the return value of the work function is
3746 // returned to the caller. If the result is Retry, then Run sleeps according to the its backoff policy
3847 // before retrying. If the total number of retries is exceeded then the return value of the work function
3948 // is returned to the caller regardless.
40 func (r *Retrier) Run(work func() error) error {
49 func (r *Retrier) RunCtx(ctx context.Context, work func(ctx context.Context) error) error {
4150 retries := 0
4251 for {
43 ret := work()
52 ret := work(ctx)
4453
4554 switch r.class.Classify(ret) {
4655 case Succeed, Fail:
4958 if retries >= len(r.backoff) {
5059 return ret
5160 }
52 time.Sleep(r.calcSleep(retries))
61
62 timeout := time.After(r.calcSleep(retries))
63 if err := r.sleep(ctx, timeout); err != nil {
64 return err
65 }
66
5367 retries++
5468 }
69 }
70 }
71
72 func (r *Retrier) sleep(ctx context.Context, t <-chan time.Time) error {
73 select {
74 case <-t:
75 return nil
76 case <-ctx.Done():
77 return ctx.Err()
5578 }
5679 }
5780
00 package retrier
11
22 import (
3 "context"
34 "errors"
45 "testing"
56 "time"
1516 return nil
1617 }
1718 return returns[i-1]
19 }
20 }
21
22 func genWorkWithCtx() func(ctx context.Context) error {
23 i = 0
24 return func(ctx context.Context) error {
25 select {
26 case <-ctx.Done():
27 return errFoo
28 default:
29 i++
30 }
31 return nil
1832 }
1933 }
2034
4256 t.Error(err)
4357 }
4458 if i != 1 {
59 t.Error("run wrong number of times")
60 }
61 }
62
63 func TestRetrierCtx(t *testing.T) {
64 ctx, cancel := context.WithCancel(context.Background())
65
66 r := New([]time.Duration{0, 10 * time.Millisecond}, WhitelistClassifier{})
67
68 err := r.RunCtx(ctx, genWorkWithCtx())
69 if err != nil {
70 t.Error(err)
71 }
72 if i != 1 {
73 t.Error("run wrong number of times")
74 }
75
76 cancel()
77
78 err = r.RunCtx(ctx, genWorkWithCtx())
79 if err != errFoo {
80 t.Error("context must be cancelled")
81 }
82 if i != 0 {
4583 t.Error("run wrong number of times")
4684 }
4785 }