-
Notifications
You must be signed in to change notification settings - Fork 1
/
retry.go
44 lines (36 loc) · 986 Bytes
/
retry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package tinkoff
import (
"context"
"math"
"math/rand"
"time"
)
type retryKey struct{}
type retryStrategy struct {
timeout retryTimeoutFunc
maxRetries int
}
func (rs *retryStrategy) do(ctx context.Context) (context.Context, error) {
retry, _ := ctx.Value(retryKey{}).(int)
if rs.maxRetries > 0 && retry >= rs.maxRetries {
return ctx, errMaxRetriesExceeded
}
select {
case <-time.After(rs.timeout(retry)):
return context.WithValue(ctx, retryKey{}, retry+1), nil
case <-ctx.Done():
return ctx, ctx.Err()
}
}
type retryTimeoutFunc func(retry int) time.Duration
func exponentialRetryTimeout(base time.Duration, factor, jitter float64) retryTimeoutFunc {
return func(retry int) time.Duration {
timeout := base * time.Duration(math.Pow(factor, float64(retry)))
return timeout * time.Duration(1+jitter*(0.5-rand.Float64()))
}
}
func constantRetryTimeout(timeout time.Duration) retryTimeoutFunc {
return func(retry int) time.Duration {
return timeout
}
}