github.com/cloudwego/hertz@v0.9.3/pkg/app/client/retry/retry.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package retry 18 19 import ( 20 "math" 21 "time" 22 23 "github.com/bytedance/gopkg/lang/fastrand" 24 ) 25 26 // Config All configurations related to retry 27 type Config struct { 28 // The maximum number of call attempt times, including the initial call 29 MaxAttemptTimes uint 30 31 // Initial retry delay time 32 Delay time.Duration 33 34 // Maximum retry delay time. When the retry time increases beyond this time, 35 // this configuration will limit the upper limit of waiting time 36 MaxDelay time.Duration 37 38 // The maximum jitter time, which takes effect when the delay policy is configured as RandomDelay 39 MaxJitter time.Duration 40 41 // Delay strategy, which can combine multiple delay strategies. such as CombineDelay(BackOffDelayPolicy, RandomDelayPolicy) or BackOffDelayPolicy,etc 42 DelayPolicy DelayPolicyFunc 43 } 44 45 func (o *Config) Apply(opts []Option) { 46 for _, op := range opts { 47 op.F(o) 48 } 49 } 50 51 // DelayPolicyFunc signature of delay policy function 52 // is called to return the delay of retry 53 type DelayPolicyFunc func(attempts uint, err error, retryConfig *Config) time.Duration 54 55 // DefaultDelayPolicy is a DelayPolicyFunc which keep 0 delay in all iterations 56 func DefaultDelayPolicy(_ uint, _ error, _ *Config) time.Duration { 57 return 0 * time.Millisecond 58 } 59 60 // FixedDelayPolicy is a DelayPolicyFunc which keeps delay the same through all iterations 61 func FixedDelayPolicy(_ uint, _ error, retryConfig *Config) time.Duration { 62 return retryConfig.Delay 63 } 64 65 // RandomDelayPolicy is a DelayPolicyFunc which picks a random delay up to RetryConfig.MaxJitter, if the retryConfig.MaxJitter less than or equal to 0, the final delay is 0 66 func RandomDelayPolicy(_ uint, _ error, retryConfig *Config) time.Duration { 67 if retryConfig.MaxJitter <= 0 { 68 return 0 * time.Millisecond 69 } 70 return time.Duration(fastrand.Int63n(int64(retryConfig.MaxJitter))) 71 } 72 73 // BackOffDelayPolicy is a DelayPolicyFunc which exponentially increases delay between consecutive retries, if the retryConfig.Delay less than or equal to 0, the final delay is 0 74 func BackOffDelayPolicy(attempts uint, _ error, retryConfig *Config) time.Duration { 75 if retryConfig.Delay <= 0 { 76 return 0 * time.Millisecond 77 } 78 // 1 << 63 would overflow signed int64 (time.Duration), thus 62. 79 const max uint = 62 80 if attempts > max { 81 attempts = max 82 } 83 84 return retryConfig.Delay << attempts 85 } 86 87 // CombineDelay return DelayPolicyFunc, which combines the optional DelayPolicyFunc into a new DelayPolicyFunc 88 func CombineDelay(delays ...DelayPolicyFunc) DelayPolicyFunc { 89 const maxInt64 = uint64(math.MaxInt64) 90 91 return func(attempts uint, err error, config *Config) time.Duration { 92 var total uint64 93 for _, delay := range delays { 94 total += uint64(delay(attempts, err, config)) 95 if total > maxInt64 { 96 total = maxInt64 97 } 98 } 99 100 return time.Duration(total) 101 } 102 } 103 104 // Delay generate the delay time required for the current retry config, if the retryConfig.DelayPolicy == nil, the final delay is 0 105 func Delay(attempts uint, err error, retryConfig *Config) time.Duration { 106 if retryConfig.DelayPolicy == nil { 107 return 0 * time.Millisecond 108 } 109 110 delayTime := retryConfig.DelayPolicy(attempts, err, retryConfig) 111 if retryConfig.MaxDelay > 0 && delayTime > retryConfig.MaxDelay { 112 delayTime = retryConfig.MaxDelay 113 } 114 return delayTime 115 }