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
14 var resultErrMu sync.Mutex
16 c := &StateChangeConf{
17 Pending: []string{"retryableerror"},
18 Target: []string{"success"},
20 MinTimeout: 500 * time.Millisecond,
21 Refresh: func() (interface{}, string, error) {
25 defer resultErrMu.Unlock()
29 return 42, "success", nil
35 return 42, "retryableerror", nil
37 return nil, "quit", rerr.Err
41 _, waitErr := c.WaitForState()
43 // Need to acquire the lock here to be able to avoid race using resultErr as
46 defer resultErrMu.Unlock()
48 // resultErr may be nil because the wait timed out and resultErr was never
49 // set; this is still an error
53 // resultErr takes precedence over waitErr if both are set because it is
54 // more likely to be useful
58 // RetryFunc is the function retried until it succeeds.
59 type RetryFunc func() *RetryError
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 {
68 // RetryableError is a helper to create a RetryError that's retryable from a
70 func RetryableError(err error) *RetryError {
74 return &RetryError{Err: err, Retryable: true}
77 // NonRetryableError is a helper to create a RetryError that's _not_ retryable
78 // from a given error.
79 func NonRetryableError(err error) *RetryError {
83 return &RetryError{Err: err, Retryable: false}