Codebase list golang-github-juju-retry / HEAD
HEAD

Tree @HEAD (Download .tar.gz)

# retry
    import "github.com/juju/retry"

The retry package encapsulates the mechanism around retrying commands.

The simple use is to call retry.Call with a function closure.

```go


	err := retry.Call(retry.CallArgs{
		Func:     func() error { ... },
		Attempts: 5,
		Delay:    time.Minute,
		Clock:    clock.WallClock,
	})

```

The bare minimum arguments that need to be specified are:
* Func - the function to call
* Attempts - the number of times to try Func before giving up, or a negative number for unlimited attempts (`retry.UnlimitedAttempts`)
* Delay - how long to wait between each try that returns an error
* Clock - either the wall clock, or some testing clock

Any error that is returned from the `Func` is considered transient.
In order to identify some errors as fatal, pass in a function for the
`IsFatalError` CallArgs value.

In order to have the `Delay` change for each iteration, a `BackoffFunc`
needs to be set on the CallArgs. A simple doubling delay function is
provided by `DoubleDelay`.

An example of a more complex `BackoffFunc` could be a stepped function such
as:

```go


	func StepDelay(last time.Duration, attempt int) time.Duration {
		switch attempt{
		case 1:
			return time.Second
		case 2:
			return 5 * time.Second
		case 3:
			return 20 * time.Second
		case 4:
			return time.Minute
		case 5:
			return 5 * time.Minute
		default:
			return 2 * last
		}
	}

```

Consider some package `foo` that has a `TryAgainError`, which looks something
like this:
```go


	type TryAgainError struct {
		After time.Duration
	}

```
and we create something that looks like this:

```go


	type TryAgainHelper struct {
		next time.Duration
	}
	
	func (h *TryAgainHelper) notify(lastError error, attempt int) {
		if tryAgain, ok := lastError.(*foo.TryAgainError); ok {
			h.next = tryAgain.After
		} else {
			h.next = 0
		}
	}
	
	func (h *TryAgainHelper) next(last time.Duration) time.Duration {
		if h.next != 0 {
			return h.next
		}
		return last
	}

```

Then we could do this:
```go


	helper := TryAgainHelper{}
	retry.Call(retry.CallArgs{
		Func: func() error {
			return foo.SomeFunc()
		},
		NotifyFunc:  helper.notify,
		BackoffFunc: helper.next,
		Attempts:    20,
		Delay:       100 * time.Millisecond,
		Clock:       clock.WallClock,
	})

```




## Constants
``` go
const (
    // UnlimitedAttempts can be used as a value for `Attempts` to clearly
    // show to the reader that there is no limit to the number of attempts.
    UnlimitedAttempts = -1
)
```


## func Call
``` go
func Call(args CallArgs) error
```
Call will repeatedly execute the Func until either the function returns no
error, the retry count is exceeded or the stop channel is closed.


## func DoubleDelay
``` go
func DoubleDelay(delay time.Duration, attempt int) time.Duration
```
DoubleDelay provides a simple function that doubles the duration passed in.
This can then be easily used as the `BackoffFunc` in the `CallArgs`
structure.


## func IsAttemptsExceeded
``` go
func IsAttemptsExceeded(err error) bool
```
IsAttemptsExceeded returns true if the error is the result of the `Call`
function finishing due to hitting the requested number of `Attempts`.


## func IsDurationExceeded
``` go
func IsDurationExceeded(err error) bool
```
IsDurationExceeded returns true if the error is the result of the `Call`
function finishing due to the total duration exceeding the specified
`MaxDuration` value.


## func IsRetryStopped
``` go
func IsRetryStopped(err error) bool
```
IsRetryStopped returns true if the error is the result of the `Call`
function finishing due to the stop channel being closed.


## func LastError
``` go
func LastError(err error) error
```
LastError retrieves the last error returned from `Func` before iteration
was terminated due to the attempt count being exceeded, the maximum
duration being exceeded, or the stop channel being closed.



## type CallArgs
``` go
type CallArgs struct {
    // Func is the function that will be retried if it returns an error result.
    Func func() error

    // IsFatalError is a function that, if set, will be called for every non-
    // nil error result from `Func`. If `IsFatalError` returns true, the error
    // is immediately returned breaking out from any further retries.
    IsFatalError func(error) bool

    // NotifyFunc is a function that is called if Func fails, and the attempt
    // number. The first time this function is called attempt is 1, the second
    // time, attempt is 2 and so on.
    NotifyFunc func(lastError error, attempt int)

    // Attempts specifies the number of times Func should be retried before
    // giving up and returning the `AttemptsExceeded` error. If a negative
    // value is specified, the `Call` will retry forever.
    Attempts int

    // Delay specifies how long to wait between retries.
    Delay time.Duration

    // MaxDelay specifies how longest time to wait between retries. If no
    // value is specified there is no maximum delay.
    MaxDelay time.Duration

    // MaxDuration specifies the maximum time the `Call` function should spend
    // iterating over `Func`. The duration is calculated from the start of the
    // `Call` function.  If the next delay time would take the total duration
    // of the call over MaxDuration, then a DurationExceeded error is
    // returned. If no value is specified, Call will continue until the number
    // of attempts is complete.
    MaxDuration time.Duration

    // BackoffFunc allows the caller to provide a function that alters the
    // delay each time through the loop. If this function is not provided the
    // delay is the same each iteration. Alternatively a function such as
    // `retry.DoubleDelay` can be used that will provide an exponential
    // backoff. The first time this function is called attempt is 1, the
    // second time, attempt is 2 and so on.
    BackoffFunc func(delay time.Duration, attempt int) time.Duration

    // Clock provides the mechanism for waiting. Normal program execution is
    // expected to use something like clock.WallClock, and tests can override
    // this to not actually sleep in tests.
    Clock clock.Clock

    // Stop is a channel that can be used to indicate that the waiting should
    // be interrupted. If Stop is nil, then the Call function cannot be interrupted.
    // If the channel is closed prior to the Call function being executed, the
    // Func is still attempted once.
    Stop <-chan struct{}
}
```
CallArgs is a simple structure used to define the behaviour of the Call
function.











### func (\*CallArgs) Validate
``` go
func (args *CallArgs) Validate() error
```
Validate the values are valid. The ensures that the Func, Delay, Attempts
and Clock have been specified.









- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)