github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/helper/resource/wait.go (about)

     1  package resource
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // Retry is a basic wrapper around StateChangeConf that will just retry
     9  // a function until it no longer returns an error.
    10  func Retry(timeout time.Duration, f RetryFunc) error {
    11  	// These are used to pull the error out of the function; need a mutex to
    12  	// avoid a data race.
    13  	var resultErr error
    14  	var resultErrMu sync.Mutex
    15  
    16  	c := &StateChangeConf{
    17  		Pending:    []string{"retryableerror"},
    18  		Target:     []string{"success"},
    19  		Timeout:    timeout,
    20  		MinTimeout: 500 * time.Millisecond,
    21  		Refresh: func() (interface{}, string, error) {
    22  			rerr := f()
    23  			if rerr == nil {
    24  				resultErr = nil
    25  				return 42, "success", nil
    26  			}
    27  
    28  			resultErrMu.Lock()
    29  			defer resultErrMu.Unlock()
    30  			resultErr = rerr.Err
    31  
    32  			if rerr.Retryable {
    33  				return 42, "retryableerror", nil
    34  			}
    35  			return nil, "quit", rerr.Err
    36  		},
    37  	}
    38  
    39  	c.WaitForState()
    40  
    41  	// Need to acquire the lock here to be able to avoid race using resultErr as
    42  	// the return value
    43  	resultErrMu.Lock()
    44  	defer resultErrMu.Unlock()
    45  	return resultErr
    46  }
    47  
    48  // RetryFunc is the function retried until it succeeds.
    49  type RetryFunc func() *RetryError
    50  
    51  // RetryError is the required return type of RetryFunc. It forces client code
    52  // to choose whether or not a given error is retryable.
    53  type RetryError struct {
    54  	Err       error
    55  	Retryable bool
    56  }
    57  
    58  // RetryableError is a helper to create a RetryError that's retryable from a
    59  // given error.
    60  func RetryableError(err error) *RetryError {
    61  	if err == nil {
    62  		return nil
    63  	}
    64  	return &RetryError{Err: err, Retryable: true}
    65  }
    66  
    67  // NonRetryableError is a helper to create a RetryError that's _not)_ retryable
    68  // from a given error.
    69  func NonRetryableError(err error) *RetryError {
    70  	if err == nil {
    71  		return nil
    72  	}
    73  	return &RetryError{Err: err, Retryable: false}
    74  }