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 }