Skip to content

Commit 9a6c9c9

Browse files
committed
[retry] Standardize package conventions
- Rename errors.go to error.go - Pass context.Context to Operation signature - Use structured logging in WithLogNotifier
1 parent 702f0a1 commit 9a6c9c9

4 files changed

Lines changed: 16 additions & 20 deletions

File tree

File renamed without changes.

retry/options.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ func WithNotifier(n func(err error, wait time.Duration)) Option {
120120
// err := retry.Do(ctx, op, retry.WithLogNotifier(l.Log))
121121
func WithLogNotifier(log logger.Handler) Option {
122122
return WithNotifier(func(err error, wait time.Duration) {
123-
log.Warnf("retry: transient error — retrying in %s: %v", wait.Round(time.Millisecond), err)
123+
log.Infof("retry: transient error — retrying in %s", wait.Round(time.Millisecond))
124+
log.Warn(err)
124125
})
125126
}

retry/retry.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//
1717
// # Basic usage
1818
//
19-
// err := retry.Do(ctx, func() error {
19+
// err := retry.Do(ctx, func(ctx context.Context) error {
2020
// req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
2121
// resp, err := http.DefaultClient.Do(req)
2222
// if err != nil {
@@ -44,14 +44,9 @@ import (
4444

4545
// Operation is the function signature for retryable work.
4646
//
47-
// TODO: The Operation signature currently lacks a context.Context, which prevents
48-
// operations from being interrupted immediately upon context cancellation.
49-
// A follow-up task should be created for the full implementation to avoid bloating
50-
// the current pull request.
51-
//
5247
// Return nil on success, [Permanent](err) to stop without further retries,
5348
// or any plain error to trigger the next backoff wait and retry.
54-
type Operation func() error
49+
type Operation func(ctx context.Context) error
5550

5651
// Do executes op with exponential backoff until one of the following occurs:
5752
// - op returns nil (success)
@@ -77,7 +72,7 @@ func Do(ctx context.Context, op Operation, opts ...Option) error {
7772
b := buildBackOff(cfg)
7873
bCtx := backoff.WithContext(b, ctx)
7974

80-
return backoff.RetryNotify(backoff.Operation(op), bCtx, cfg.Notifier)
75+
return backoff.RetryNotify(func() error { return op(ctx) }, bCtx, cfg.Notifier)
8176
}
8277

8378
// buildBackOff constructs a cenkalti/backoff policy from the supplied Config.

retry/retry_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import (
1515

1616
// alwaysFail returns an Operation that always returns the given error.
1717
func alwaysFail(err error) retry.Operation {
18-
return func() error { return err }
18+
return func(ctx context.Context) error { return err }
1919
}
2020

2121
// countingOp returns an Operation that always fails and increments *count.
2222
func countingOp(count *atomic.Int64, err error) retry.Operation {
23-
return func() error {
23+
return func(ctx context.Context) error {
2424
count.Add(1)
2525
return err
2626
}
@@ -32,7 +32,7 @@ func TestDo_SucceedsFirstAttempt(t *testing.T) {
3232
t.Parallel()
3333

3434
calls := 0
35-
err := retry.Do(context.Background(), func() error {
35+
err := retry.Do(context.Background(), func(ctx context.Context) error {
3636
calls++
3737
return nil
3838
}, retry.WithMaxAttempts(5))
@@ -52,7 +52,7 @@ func TestDo_SucceedsAfterTransientErrors(t *testing.T) {
5252
var calls atomic.Int64
5353

5454
err := retry.Do(context.Background(),
55-
func() error {
55+
func(ctx context.Context) error {
5656
n := calls.Add(1)
5757
if n < 4 {
5858
return transient
@@ -80,7 +80,7 @@ func TestDo_PermanentErrorStopsImmediately(t *testing.T) {
8080
calls := 0
8181

8282
err := retry.Do(context.Background(),
83-
func() error {
83+
func(ctx context.Context) error {
8484
calls++
8585
return retry.Permanent(permanent)
8686
},
@@ -143,7 +143,7 @@ func TestDo_ContextCancellationStopsLoop(t *testing.T) {
143143
}()
144144

145145
err := retry.Do(ctx,
146-
func() error {
146+
func(ctx context.Context) error {
147147
calls.Add(1)
148148
return transient
149149
},
@@ -167,7 +167,7 @@ func TestDo_ContextAlreadyCancelledBeforeFirstAttempt(t *testing.T) {
167167

168168
var calls atomic.Int64
169169
err := retry.Do(ctx,
170-
func() error {
170+
func(ctx context.Context) error {
171171
calls.Add(1)
172172
return errors.New("should not reach")
173173
},
@@ -247,7 +247,7 @@ func TestDo_NotifierCalledOnEachRetry(t *testing.T) {
247247

248248
var calls atomic.Int64
249249
_ = retry.Do(context.Background(),
250-
func() error {
250+
func(ctx context.Context) error {
251251
if calls.Add(1) <= failures {
252252
return transient
253253
}
@@ -269,7 +269,7 @@ func TestDo_NotifierNotCalledOnImmediateSuccess(t *testing.T) {
269269

270270
var notifyCount atomic.Int64
271271
_ = retry.Do(context.Background(),
272-
func() error { return nil },
272+
func(ctx context.Context) error { return nil },
273273
retry.WithNotifier(func(err error, wait time.Duration) {
274274
notifyCount.Add(1)
275275
}),
@@ -284,7 +284,7 @@ func TestDo_NotifierNotCalledOnPermanentError(t *testing.T) {
284284

285285
var notifyCount atomic.Int64
286286
_ = retry.Do(context.Background(),
287-
func() error { return retry.Permanent(errors.New("perm")) },
287+
func(ctx context.Context) error { return retry.Permanent(errors.New("perm")) },
288288
retry.WithMaxAttempts(5),
289289
retry.WithInitialInterval(1*time.Millisecond),
290290
retry.WithNotifier(func(err error, wait time.Duration) {
@@ -345,7 +345,7 @@ func TestDo_DefaultsAreApplied(t *testing.T) {
345345
defer cancel()
346346

347347
_ = retry.Do(ctx,
348-
func() error {
348+
func(ctx context.Context) error {
349349
if calls.Add(1) >= 2 {
350350
return nil
351351
}

0 commit comments

Comments
 (0)