github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/backoff.go (about) 1 package f 2 3 import ( 4 "context" 5 "github.com/cenkalti/backoff/v4" 6 "github.com/go-resty/resty/v2" 7 "time" 8 ) 9 10 // RetryOperation retry operation manager. 11 type RetryOperation struct { 12 backoff.Operation 13 *backoff.ExponentialBackOff 14 ctx context.Context 15 } 16 17 var ( 18 // Call Periods: 1s,2s,4s,8s,16s,32s,1m,1m,1m... 24h=1day 19 RetryPeriodOf1s1m1d = &RetryPeriodDuration{ 20 InitialInterval: time.Second, 21 MaxInterval: time.Minute, 22 MaxElapsedTime: 24 * time.Hour, 23 RandomFactor: 0.02, 24 Multiplier: 2.0, 25 } 26 ) 27 28 // RetryPeriodDuration With Periods. 29 type RetryPeriodDuration struct { 30 InitialInterval time.Duration 31 MaxInterval, MaxElapsedTime time.Duration 32 RandomFactor, Multiplier float64 33 } 34 35 // NewRetryOperationWithPeriod create a retryOperation with the context. 36 func NewRetryOperationWithPeriod(operation func() error, period *RetryPeriodDuration, ctx ...context.Context) *RetryOperation { 37 return NewRetryOperation(operation, period.InitialInterval, period.MaxInterval, period.MaxElapsedTime, period.RandomFactor, period.Multiplier, ctx...) 38 } 39 40 // NewRetryOperation create a retryOperation with the context. 41 func NewRetryOperation(operation func() error, 42 initialInterval, maxInterval, maxElapsedTime time.Duration, randomizationFactor, multiplier float64, 43 ctx ...context.Context) *RetryOperation { 44 var o backoff.Operation 45 if operation != nil { 46 o = operation 47 } else { 48 o = func() error { return nil } 49 } 50 if initialInterval == 0 { 51 initialInterval = backoff.DefaultInitialInterval 52 } 53 if maxInterval == 0 { 54 maxInterval = backoff.DefaultMaxInterval 55 } 56 if maxElapsedTime == 0 { 57 maxElapsedTime = backoff.DefaultMaxElapsedTime 58 } 59 if randomizationFactor == 0 { 60 randomizationFactor = backoff.DefaultRandomizationFactor 61 } 62 if multiplier == 0 { 63 multiplier = backoff.DefaultMultiplier 64 } 65 b := &backoff.ExponentialBackOff{ 66 InitialInterval: initialInterval, 67 RandomizationFactor: randomizationFactor, 68 Multiplier: multiplier, 69 MaxInterval: maxInterval, 70 MaxElapsedTime: maxElapsedTime, 71 Stop: backoff.Stop, 72 Clock: backoff.SystemClock, 73 } 74 var c context.Context 75 if len(ctx) == 1 { 76 c = ctx[0] 77 } else { 78 c = context.Background() 79 } 80 b.Reset() 81 return &RetryOperation{o, b, c} 82 } 83 84 func (ro *RetryOperation) Context() context.Context { 85 return ro.ctx 86 } 87 88 func (ro *RetryOperation) NextBackOff() time.Duration { 89 select { 90 case <-ro.ctx.Done(): 91 return backoff.Stop 92 default: 93 } 94 next := ro.ExponentialBackOff.NextBackOff() 95 if deadline, ok := ro.ctx.Deadline(); ok && deadline.Sub(time.Now()) < next { 96 return backoff.Stop 97 } 98 return next 99 } 100 101 // Retry the operation o until it does not return error or BackOff stops. 102 func (ro *RetryOperation) Retry() error { 103 return backoff.Retry(ro.Operation, ro) 104 } 105 106 // NewRetryConditionRequest create a retry http request. 107 // https://github.com/go-resty/resty#retries 108 func NewRetryConditionRequest(condition func(*resty.Response, error) bool, settings ...func(client *resty.Client)) *resty.Request { 109 if condition == nil { 110 condition = func(response *resty.Response, err error) bool { return false } 111 } 112 client := resty.New() 113 if len(settings) > 0 { 114 settings[0](client) 115 } 116 return client.AddRetryCondition(condition).R() 117 } 118 119 // NewRetryTimesRequest create a retry http request. 120 // https://github.com/go-resty/resty#retries 121 func NewRetryTimesRequest(maxRetries int, waitTime, maxWaitTime time.Duration, settings ...func(client *resty.Client)) *resty.Request { 122 if maxRetries < 1 { 123 maxRetries = 1 124 } 125 if waitTime < time.Millisecond { 126 waitTime = 100 * time.Millisecond 127 } 128 if maxWaitTime < time.Second { 129 waitTime = 2 * time.Second 130 } 131 client := resty.New() 132 for _, setting := range settings { 133 setting(client) 134 } 135 return client.SetRetryCount(maxRetries).SetRetryWaitTime(waitTime).SetRetryMaxWaitTime(maxWaitTime).R() 136 }