github.com/cloudwego/kitex@v0.9.0/pkg/retry/failure.go (about) 1 /* 2 * Copyright 2021 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 "fmt" 21 "time" 22 23 "github.com/bytedance/gopkg/lang/fastrand" 24 25 "github.com/cloudwego/kitex/pkg/rpcinfo" 26 ) 27 28 const maxFailureRetryTimes = 5 29 30 // NewFailurePolicy init default failure retry policy 31 func NewFailurePolicy() *FailurePolicy { 32 p := &FailurePolicy{ 33 StopPolicy: StopPolicy{ 34 MaxRetryTimes: 2, 35 DisableChainStop: false, 36 CBPolicy: CBPolicy{ 37 ErrorRate: defaultCBErrRate, 38 }, 39 }, 40 BackOffPolicy: &BackOffPolicy{BackOffType: NoneBackOffType}, 41 } 42 return p 43 } 44 45 // NewFailurePolicyWithResultRetry init failure retry policy with ShouldResultRetry 46 func NewFailurePolicyWithResultRetry(rr *ShouldResultRetry) *FailurePolicy { 47 fp := NewFailurePolicy() 48 fp.ShouldResultRetry = rr 49 return fp 50 } 51 52 // WithMaxRetryTimes default is 2, not include first call 53 func (p *FailurePolicy) WithMaxRetryTimes(retryTimes int) { 54 if retryTimes < 0 || retryTimes > maxFailureRetryTimes { 55 panic(fmt.Errorf("maxFailureRetryTimes is %d", maxFailureRetryTimes)) 56 } 57 p.StopPolicy.MaxRetryTimes = retryTimes 58 } 59 60 // WithMaxDurationMS include first call and retry call, if the total duration exceed limit then stop retry 61 func (p *FailurePolicy) WithMaxDurationMS(maxMS uint32) { 62 p.StopPolicy.MaxDurationMS = maxMS 63 } 64 65 // DisableChainRetryStop disables chain stop 66 func (p *FailurePolicy) DisableChainRetryStop() { 67 p.StopPolicy.DisableChainStop = true 68 } 69 70 // WithDDLStop sets ddl stop to true. 71 func (p *FailurePolicy) WithDDLStop() { 72 p.StopPolicy.DDLStop = true 73 } 74 75 // WithFixedBackOff set fixed time. 76 func (p *FailurePolicy) WithFixedBackOff(fixMS int) { 77 if err := checkFixedBackOff(fixMS); err != nil { 78 panic(err) 79 } 80 p.BackOffPolicy = &BackOffPolicy{FixedBackOffType, make(map[BackOffCfgKey]float64, 1)} 81 p.BackOffPolicy.CfgItems[FixMSBackOffCfgKey] = float64(fixMS) 82 } 83 84 // WithRandomBackOff sets the random time. 85 func (p *FailurePolicy) WithRandomBackOff(minMS, maxMS int) { 86 if err := checkRandomBackOff(minMS, maxMS); err != nil { 87 panic(err) 88 } 89 p.BackOffPolicy = &BackOffPolicy{RandomBackOffType, make(map[BackOffCfgKey]float64, 2)} 90 p.BackOffPolicy.CfgItems[MinMSBackOffCfgKey] = float64(minMS) 91 p.BackOffPolicy.CfgItems[MaxMSBackOffCfgKey] = float64(maxMS) 92 } 93 94 // WithRetryBreaker sets the error rate. 95 func (p *FailurePolicy) WithRetryBreaker(errRate float64) { 96 p.StopPolicy.CBPolicy.ErrorRate = errRate 97 if err := checkCBErrorRate(&p.StopPolicy.CBPolicy); err != nil { 98 panic(err) 99 } 100 } 101 102 // WithRetrySameNode sets to retry the same node. 103 func (p *FailurePolicy) WithRetrySameNode() { 104 p.RetrySameNode = true 105 } 106 107 // WithSpecifiedResultRetry sets customized ShouldResultRetry. 108 func (p *FailurePolicy) WithSpecifiedResultRetry(rr *ShouldResultRetry) { 109 if rr != nil { 110 p.ShouldResultRetry = rr 111 } 112 } 113 114 // String prints human readable information. 115 func (p FailurePolicy) String() string { 116 return fmt.Sprintf("{StopPolicy:%+v BackOffPolicy:%+v RetrySameNode:%+v "+ 117 "ShouldResultRetry:{ErrorRetry:%t, RespRetry:%t}}", p.StopPolicy, p.BackOffPolicy, p.RetrySameNode, p.IsErrorRetryNonNil(), p.IsRespRetryNonNil()) 118 } 119 120 // AllErrorRetry is common choice for ShouldResultRetry. 121 func AllErrorRetry() *ShouldResultRetry { 122 return &ShouldResultRetry{ErrorRetry: func(err error, ri rpcinfo.RPCInfo) bool { 123 return err != nil 124 }} 125 } 126 127 // BackOff is the interface of back off implements 128 type BackOff interface { 129 Wait(callTimes int) 130 } 131 132 // NoneBackOff means there's no backoff. 133 var NoneBackOff = &noneBackOff{} 134 135 func newFixedBackOff(fixMS int) BackOff { 136 return &fixedBackOff{ 137 fixMS: fixMS, 138 } 139 } 140 141 func newRandomBackOff(minMS, maxMS int) BackOff { 142 return &randomBackOff{ 143 minMS: minMS, 144 maxMS: maxMS, 145 } 146 } 147 148 type noneBackOff struct{} 149 150 // String prints human readable information. 151 func (p noneBackOff) String() string { 152 return "NoneBackOff" 153 } 154 155 // Wait implements the BackOff interface. 156 func (p *noneBackOff) Wait(callTimes int) { 157 } 158 159 type fixedBackOff struct { 160 fixMS int 161 } 162 163 // Wait implements the BackOff interface. 164 func (p *fixedBackOff) Wait(callTimes int) { 165 time.Sleep(time.Duration(p.fixMS) * time.Millisecond) 166 } 167 168 // String prints human readable information. 169 func (p fixedBackOff) String() string { 170 return fmt.Sprintf("FixedBackOff(%dms)", p.fixMS) 171 } 172 173 type randomBackOff struct { 174 minMS int 175 maxMS int 176 } 177 178 func (p *randomBackOff) randomDuration() time.Duration { 179 return time.Duration(p.minMS+fastrand.Intn(p.maxMS-p.minMS)) * time.Millisecond 180 } 181 182 // Wait implements the BackOff interface. 183 func (p *randomBackOff) Wait(callTimes int) { 184 time.Sleep(p.randomDuration()) 185 } 186 187 // String prints human readable information. 188 func (p randomBackOff) String() string { 189 return fmt.Sprintf("RandomBackOff(%dms-%dms)", p.minMS, p.maxMS) 190 } 191 192 func checkFixedBackOff(fixMS int) error { 193 if fixMS == 0 { 194 return fmt.Errorf("invalid FixedBackOff, fixMS=%d", fixMS) 195 } 196 return nil 197 } 198 199 func checkRandomBackOff(minMS, maxMS int) error { 200 if maxMS <= minMS { 201 return fmt.Errorf("invalid RandomBackOff, minMS=%d, maxMS=%d", minMS, maxMS) 202 } 203 return nil 204 }