Skip to content

Commit fd070fe

Browse files
authored
feat: retry with ctx deadline (zeromicro#3626)
1 parent 4f22034 commit fd070fe

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

.codecov.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
coverage:
2+
status:
3+
patch: true
4+
project: false # disabled because project coverage is not stable
15
comment:
26
layout: "flags, files"
37
behavior: once

core/fx/retry.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@ package fx
22

33
import (
44
"context"
5-
"errors"
65
"time"
76

87
"github.com/zeromicro/go-zero/core/errorx"
98
)
109

1110
const defaultRetryTimes = 3
1211

13-
var errTimeout = errors.New("retry timeout")
14-
1512
type (
1613
// RetryOption defines the method to customize DoWithRetry.
1714
RetryOption func(*retryOptions)
@@ -28,7 +25,7 @@ type (
2825
// and performs modification operations, it is best to lock them,
2926
// otherwise there may be data race issues
3027
func DoWithRetry(fn func() error, opts ...RetryOption) error {
31-
return retry(func(errChan chan error, retryCount int) {
28+
return retry(context.Background(), func(errChan chan error, retryCount int) {
3229
errChan <- fn()
3330
}, opts...)
3431
}
@@ -40,20 +37,19 @@ func DoWithRetry(fn func() error, opts ...RetryOption) error {
4037
// otherwise there may be data race issues
4138
func DoWithRetryCtx(ctx context.Context, fn func(ctx context.Context, retryCount int) error,
4239
opts ...RetryOption) error {
43-
return retry(func(errChan chan error, retryCount int) {
40+
return retry(ctx, func(errChan chan error, retryCount int) {
4441
errChan <- fn(ctx, retryCount)
4542
}, opts...)
4643
}
4744

48-
func retry(fn func(errChan chan error, retryCount int), opts ...RetryOption) error {
45+
func retry(ctx context.Context, fn func(errChan chan error, retryCount int), opts ...RetryOption) error {
4946
options := newRetryOptions()
5047
for _, opt := range opts {
5148
opt(options)
5249
}
5350

5451
var berr errorx.BatchError
5552
var cancelFunc context.CancelFunc
56-
ctx := context.Background()
5753
if options.timeout > 0 {
5854
ctx, cancelFunc = context.WithTimeout(ctx, options.timeout)
5955
defer cancelFunc()
@@ -71,14 +67,14 @@ func retry(fn func(errChan chan error, retryCount int), opts ...RetryOption) err
7167
return nil
7268
}
7369
case <-ctx.Done():
74-
berr.Add(errTimeout)
70+
berr.Add(ctx.Err())
7571
return berr.Err()
7672
}
7773

7874
if options.interval > 0 {
7975
select {
8076
case <-ctx.Done():
81-
berr.Add(errTimeout)
77+
berr.Add(ctx.Err())
8278
return berr.Err()
8379
case <-time.After(options.interval):
8480
}

core/fx/retry_test.go

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,51 @@ func TestRetryWithInterval(t *testing.T) {
9898
}
9999

100100
func TestRetryCtx(t *testing.T) {
101-
assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
102-
if retryCount == 0 {
101+
t.Run("with timeout", func(t *testing.T) {
102+
assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
103+
if retryCount == 0 {
104+
return errors.New("any")
105+
}
106+
time.Sleep(time.Millisecond * 150)
107+
return nil
108+
}, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
109+
110+
assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
111+
if retryCount == 1 {
112+
return nil
113+
}
114+
time.Sleep(time.Millisecond * 150)
115+
return errors.New("any ")
116+
}, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
117+
})
118+
119+
t.Run("with deadline exceeded", func(t *testing.T) {
120+
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond*250))
121+
defer cancel()
122+
123+
var times int
124+
assert.Error(t, DoWithRetryCtx(ctx, func(ctx context.Context, retryCount int) error {
125+
times++
126+
time.Sleep(time.Millisecond * 150)
103127
return errors.New("any")
104-
}
105-
time.Sleep(time.Millisecond * 150)
106-
return nil
107-
}, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
128+
}, WithInterval(time.Millisecond*150)))
129+
assert.Equal(t, 1, times)
130+
})
108131

109-
assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
110-
if retryCount == 1 {
111-
return nil
112-
}
113-
time.Sleep(time.Millisecond * 150)
114-
return errors.New("any ")
115-
}, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
132+
t.Run("with deadline not exceeded", func(t *testing.T) {
133+
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond*250))
134+
defer cancel()
135+
136+
var times int
137+
assert.NoError(t, DoWithRetryCtx(ctx, func(ctx context.Context, retryCount int) error {
138+
times++
139+
if times == defaultRetryTimes {
140+
return nil
141+
}
142+
143+
time.Sleep(time.Millisecond * 50)
144+
return errors.New("any")
145+
}))
146+
assert.Equal(t, defaultRetryTimes, times)
147+
})
116148
}

0 commit comments

Comments
 (0)