github.phpd.cn/hashicorp/packer@v1.3.2/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  }