github.com/lastbackend/toolkit@v0.0.0-20241020043710-cafa37b95aad/pkg/util/backoff/backoff.go (about) 1 /* 2 Copyright [2014] - [2023] The Last.Backend 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 backoff 18 19 import ( 20 "math" 21 "sync/atomic" 22 "time" 23 ) 24 25 const maxInt64 = float64(math.MaxInt64 - 512) 26 27 type Backoff struct { 28 attempt uint64 29 // Factor are the multiplication factor 30 Factor float64 31 // Min and Max are the minimum and maximum counter values. 32 Min, Max time.Duration 33 } 34 35 func (b *Backoff) Duration() time.Duration { 36 d := b.ForAttempt(float64(atomic.AddUint64(&b.attempt, 1) - 1)) 37 return d 38 } 39 40 func (b *Backoff) ForAttempt(attempt float64) time.Duration { 41 min := b.Min 42 if min <= 0 { 43 min = 100 * time.Millisecond 44 } 45 max := b.Max 46 if max <= 0 { 47 max = 10 * time.Second 48 } 49 if min >= max { 50 return max 51 } 52 53 factor := b.Factor 54 if factor <= 0 { 55 factor = 2 56 } 57 58 duration := float64(min) * math.Pow(factor, attempt) 59 60 if duration > maxInt64 { 61 return max 62 } 63 64 d := time.Duration(duration) 65 if d < min { 66 return min 67 } 68 if d > max { 69 return max 70 } 71 return d 72 } 73 74 func (b *Backoff) Reset() { 75 atomic.StoreUint64(&b.attempt, 0) 76 } 77 78 func (b *Backoff) Attempt() float64 { 79 return float64(atomic.LoadUint64(&b.attempt)) 80 }