github.com/memsql/terraform@v0.7.0-rc2.0.20160706152241-21e2173e0a32/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 _, waitErr := 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 46 // resultErr may be nil because the wait timed out and resultErr was never 47 // set; this is still an error 48 if resultErr == nil { 49 return waitErr 50 } 51 // resultErr takes precedence over waitErr if both are set because it is 52 // more likely to be useful 53 return resultErr 54 } 55 56 // RetryFunc is the function retried until it succeeds. 57 type RetryFunc func() *RetryError 58 59 // RetryError is the required return type of RetryFunc. It forces client code 60 // to choose whether or not a given error is retryable. 61 type RetryError struct { 62 Err error 63 Retryable bool 64 } 65 66 // RetryableError is a helper to create a RetryError that's retryable from a 67 // given error. 68 func RetryableError(err error) *RetryError { 69 if err == nil { 70 return nil 71 } 72 return &RetryError{Err: err, Retryable: true} 73 } 74 75 // NonRetryableError is a helper to create a RetryError that's _not)_ retryable 76 // from a given error. 77 func NonRetryableError(err error) *RetryError { 78 if err == nil { 79 return nil 80 } 81 return &RetryError{Err: err, Retryable: false} 82 }