github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/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  // Retry retries a function up to numTries times with exponential backoff.
    12  // If numTries == 0, retry indefinitely. If interval == 0, Retry will not delay retrying and there will be
    13  // no exponential backoff. If maxInterval == 0, maxInterval is set to +Infinity.
    14  // Intervals are in seconds.
    15  // Returns an error if initial > max intervals, if retries are exhausted, or if the passed function returns
    16  // an error.
    17  func Retry(initialInterval float64, maxInterval float64, numTries uint, function func() (bool, error)) error {
    18  	if maxInterval == 0 {
    19  		maxInterval = math.Inf(1)
    20  	} else if initialInterval < 0 || initialInterval > maxInterval {
    21  		return fmt.Errorf("Invalid retry intervals (negative or initial < max). Initial: %f, Max: %f.", initialInterval, maxInterval)
    22  	}
    23  
    24  	var err error
    25  	done := false
    26  	interval := initialInterval
    27  	for i := uint(0); !done && (numTries == 0 || i < numTries); i++ {
    28  		done, err = function()
    29  		if err != nil {
    30  			return err
    31  		}
    32  
    33  		if !done {
    34  			// Retry after delay. Calculate next delay.
    35  			time.Sleep(time.Duration(interval) * time.Second)
    36  			interval = math.Min(interval*2, maxInterval)
    37  		}
    38  	}
    39  
    40  	if !done {
    41  		return RetryExhaustedError
    42  	}
    43  	return nil
    44  }