Skip to content

Commit 750bdb5

Browse files
committed
Update the retry logic to make the first call without branching out to a coroutine
1 parent 919ec18 commit 750bdb5

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

workflow/retries.go

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,20 @@ var DefaultRetryOptions = RetryOptions{
3030
}
3131

3232
func withRetries[T any](ctx sync.Context, retryOptions RetryOptions, fn func(ctx sync.Context, attempt int) Future[T]) Future[T] {
33+
attempt := 0
34+
firstAttempt := Now(ctx)
35+
36+
f := fn(ctx, attempt)
37+
3338
if retryOptions.MaxAttempts <= 1 {
3439
// Short-circuit if we don't need to retry
35-
return fn(ctx, 0)
40+
return f
3641
}
3742

43+
// Start a separate co-routine for retries
3844
r := sync.NewFuture[T]()
3945

4046
sync.Go(ctx, func(ctx sync.Context) {
41-
firstAttempt := Now(ctx)
42-
4347
var result T
4448
var err error
4549

@@ -48,32 +52,38 @@ func withRetries[T any](ctx sync.Context, retryOptions RetryOptions, fn func(ctx
4852
retryExpiration = firstAttempt.Add(retryOptions.RetryTimeout)
4953
}
5054

51-
for attempt := 0; attempt < retryOptions.MaxAttempts; attempt++ {
52-
if !retryExpiration.IsZero() && Now(ctx).After(retryExpiration) {
53-
// Reached maximum retry time, abort retries
55+
for {
56+
// Wait for active operation to finish
57+
result, err = f.Get(ctx)
58+
if err == nil {
5459
break
5560
}
5661

57-
result, err = fn(ctx, attempt).Get(ctx)
58-
if err != nil {
59-
if err == sync.Canceled {
60-
break
61-
}
62+
if err == sync.Canceled {
63+
break
64+
}
6265

63-
backoffDuration := time.Duration(float64(retryOptions.FirstRetryInterval) * math.Pow(retryOptions.BackoffCoefficient, float64(attempt)))
64-
if retryOptions.MaxRetryInterval > 0 {
65-
backoffDuration = time.Duration(math.Min(float64(backoffDuration), float64(retryOptions.MaxRetryInterval)))
66-
}
66+
backoffDuration := time.Duration(float64(retryOptions.FirstRetryInterval) * math.Pow(retryOptions.BackoffCoefficient, float64(attempt)))
67+
if retryOptions.MaxRetryInterval > 0 {
68+
backoffDuration = time.Duration(math.Min(float64(backoffDuration), float64(retryOptions.MaxRetryInterval)))
69+
}
6770

68-
if err := Sleep(ctx, backoffDuration); err != nil {
69-
r.Set(*new(T), err)
70-
return
71-
}
71+
if err := Sleep(ctx, backoffDuration); err != nil {
72+
r.Set(*new(T), err)
73+
return
74+
}
7275

73-
continue
76+
if !retryExpiration.IsZero() && Now(ctx).After(retryExpiration) {
77+
// Reached maximum retry time, abort retries
78+
break
79+
}
80+
81+
attempt++
82+
if attempt >= retryOptions.MaxAttempts {
83+
break
7484
}
7585

76-
break
86+
f = fn(ctx, attempt+1)
7787
}
7888

7989
r.Set(result, err)

0 commit comments

Comments
 (0)