github.com/gavriloga/terraform@v0.11.12-beta1/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 24 resultErrMu.Lock() 25 defer resultErrMu.Unlock() 26 27 if rerr == nil { 28 resultErr = nil 29 return 42, "success", nil 30 } 31 32 resultErr = rerr.Err 33 34 if rerr.Retryable { 35 return 42, "retryableerror", nil 36 } 37 return nil, "quit", rerr.Err 38 }, 39 } 40 41 _, waitErr := c.WaitForState() 42 43 // Need to acquire the lock here to be able to avoid race using resultErr as 44 // the return value 45 resultErrMu.Lock() 46 defer resultErrMu.Unlock() 47 48 // resultErr may be nil because the wait timed out and resultErr was never 49 // set; this is still an error 50 if resultErr == nil { 51 return waitErr 52 } 53 // resultErr takes precedence over waitErr if both are set because it is 54 // more likely to be useful 55 return resultErr 56 } 57 58 // RetryFunc is the function retried until it succeeds. 59 type RetryFunc func() *RetryError 60 61 // RetryError is the required return type of RetryFunc. It forces client code 62 // to choose whether or not a given error is retryable. 63 type RetryError struct { 64 Err error 65 Retryable bool 66 } 67 68 // RetryableError is a helper to create a RetryError that's retryable from a 69 // given error. 70 func RetryableError(err error) *RetryError { 71 if err == nil { 72 return nil 73 } 74 return &RetryError{Err: err, Retryable: true} 75 } 76 77 // NonRetryableError is a helper to create a RetryError that's _not_ retryable 78 // from a given error. 79 func NonRetryableError(err error) *RetryError { 80 if err == nil { 81 return nil 82 } 83 return &RetryError{Err: err, Retryable: false} 84 }