waiter.go (1910B)
1 package waiter 2 3 import ( 4 "fmt" 5 "math" 6 "time" 7 8 "github.com/aws/smithy-go/rand" 9 ) 10 11 // ComputeDelay computes delay between waiter attempts. The function takes in a current attempt count, 12 // minimum delay, maximum delay, and remaining wait time for waiter as input. The inputs minDelay and maxDelay 13 // must always be greater than 0, along with minDelay lesser than or equal to maxDelay. 14 // 15 // Returns the computed delay and if next attempt count is possible within the given input time constraints. 16 // Note that the zeroth attempt results in no delay. 17 func ComputeDelay(attempt int64, minDelay, maxDelay, remainingTime time.Duration) (delay time.Duration, err error) { 18 // zeroth attempt, no delay 19 if attempt <= 0 { 20 return 0, nil 21 } 22 23 // remainingTime is zero or less, no delay 24 if remainingTime <= 0 { 25 return 0, nil 26 } 27 28 // validate min delay is greater than 0 29 if minDelay == 0 { 30 return 0, fmt.Errorf("minDelay must be greater than zero when computing Delay") 31 } 32 33 // validate max delay is greater than 0 34 if maxDelay == 0 { 35 return 0, fmt.Errorf("maxDelay must be greater than zero when computing Delay") 36 } 37 38 // Get attempt ceiling to prevent integer overflow. 39 attemptCeiling := (math.Log(float64(maxDelay/minDelay)) / math.Log(2)) + 1 40 41 if attempt > int64(attemptCeiling) { 42 delay = maxDelay 43 } else { 44 // Compute exponential delay based on attempt. 45 ri := 1 << uint64(attempt-1) 46 // compute delay 47 delay = minDelay * time.Duration(ri) 48 } 49 50 if delay != minDelay { 51 // randomize to get jitter between min delay and delay value 52 d, err := rand.CryptoRandInt63n(int64(delay - minDelay)) 53 if err != nil { 54 return 0, fmt.Errorf("error computing retry jitter, %w", err) 55 } 56 57 delay = time.Duration(d) + minDelay 58 } 59 60 // check if this is the last attempt possible and compute delay accordingly 61 if remainingTime-delay <= minDelay { 62 delay = remainingTime - minDelay 63 } 64 65 return delay, nil 66 }