src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }