github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/common/retry.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "math" 6 "time" 7 ) 8 9 var RetryExhaustedError error = fmt.Errorf("Function never succeeded in Retry") 10 11 // RetryableFunc performs an action and returns a bool indicating whether the 12 // function is done, or if it should keep retrying, and an error which will 13 // abort the retry and be returned by the Retry function. The 0-indexed attempt 14 // is passed with each call. 15 type RetryableFunc func(uint) (bool, error) 16 17 /* 18 Retry retries a function up to numTries times with exponential backoff. 19 If numTries == 0, retry indefinitely. 20 If interval == 0, Retry will not delay retrying and there will be no 21 exponential backoff. 22 If maxInterval == 0, maxInterval is set to +Infinity. 23 Intervals are in seconds. 24 Returns an error if initial > max intervals, if retries are exhausted, or if the passed function returns 25 an error. 26 */ 27 func Retry(initialInterval float64, maxInterval float64, numTries uint, function RetryableFunc) error { 28 if maxInterval == 0 { 29 maxInterval = math.Inf(1) 30 } else if initialInterval < 0 || initialInterval > maxInterval { 31 return fmt.Errorf("Invalid retry intervals (negative or initial < max). Initial: %f, Max: %f.", initialInterval, maxInterval) 32 } 33 34 var err error 35 done := false 36 interval := initialInterval 37 for i := uint(0); !done && (numTries == 0 || i < numTries); i++ { 38 done, err = function(i) 39 if err != nil { 40 return err 41 } 42 43 if !done { 44 // Retry after delay. Calculate next delay. 45 time.Sleep(time.Duration(interval) * time.Second) 46 interval = math.Min(interval*2, maxInterval) 47 } 48 } 49 50 if !done { 51 return RetryExhaustedError 52 } 53 return nil 54 }