retry

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2020 License: Apache-2.0 Imports: 3 Imported by: 2

README

Retry

License GitHub go.mod Go version go.dev reference Build Status Coverage Status Go Report Card

This library supports Go >= 1.13.

Retry calls your function, and if it errors it calls it again with a delay. Eventually it returns the last error or nil if one call is successful.

l := &retry.Retry{
    Attempts: 666,
    Delay:    time.Millisecond,
}
err := l.Do(func() error {
    // do some work.
    return nil
})

If you want to stop retrying you can return a special error:

err := l.Do(func() error {
    if specialCase {
        return &retry.StopError{
            Err: errors.New("a special stop"),
        }
    }
    return nil
})

The standard behaviour is to delay the amount you set. You can pass any function with this signature to change the delay behaviour:

func(attempt int, delay time.Duration) time.Duration

You can also pass the retry.IncrementalDelay function that would increase the delay with a jitter to prevent Thundering herd.

l := &retry.Retry{
    Attempts: 666,
    Delay:    10 * time.Millisecond,
    Method:   retry.IncrementalDelay,
}
err := l.Do(func() error {
    if specialCase {
        return &retry.StopError{
            Err: errors.New("a special stop"),
        }
    }
    return nil
})

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IncrementalDelay

func IncrementalDelay(attempt int, delay time.Duration) time.Duration

IncrementalDelay increases the delay between attempts. It adds a jitter to prevent Thundering herd.

func StandardDelay

func StandardDelay(_ int, delay time.Duration) time.Duration

StandardDelay always delays the same amount of time.

Types

type DelayMethod

type DelayMethod func(attempt int, delay time.Duration) time.Duration

DelayMethod determines how the delay behaves. The current attempt is passed on each iteration, with the delay value of the Retry object.

type Retry

type Retry struct {
	Attempts int
	Delay    time.Duration
	Method   DelayMethod
}

Retry implements a Do method that would call a given function Attempts times until it returns nil. It will delay between calls for any errors based on the provided Method. Retry is concurrent safe. The zero value does not do anything.

func (Retry) Do

func (r Retry) Do(fn func() error) error

Do calls fn for Attempts times until it returns nil or a StopError. If retries is 0 fn would not be called. It delays and retries if the fn returns any errors or panics.

Example
package main

import (
	"fmt"

	"github.com/arsham/retry"
)

func main() {
	l := &retry.Retry{
		Attempts: 4,
	}
	err := l.Do(func() error {
		return nil
	})
	fmt.Println("Error:", err)

}
Output:

Error: <nil>
Example (Error)
package main

import (
	"fmt"
	"time"

	"github.com/arsham/retry"
	"github.com/pkg/errors"
)

func main() {
	l := &retry.Retry{
		Attempts: 4,
		Delay:    time.Nanosecond,
	}
	err := l.Do(func() error {
		return errors.New("some error")
	})
	fmt.Println("Error:", err)

}
Output:

Error: some error
Example (Incremental)
package main

import (
	"fmt"
	"time"

	"github.com/arsham/retry"
	"github.com/pkg/errors"
)

func main() {
	l := &retry.Retry{
		Attempts: 4,
		Delay:    time.Nanosecond,
		Method:   retry.IncrementalDelay,
	}
	i := 0
	err := l.Do(func() error {
		i++
		if i < 3 {
			return errors.New("ignored error")
		}
		return nil
	})
	fmt.Println("Error:", err)

}
Output:

Error: <nil>
Example (Standard)
package main

import (
	"fmt"
	"time"

	"github.com/arsham/retry"
	"github.com/pkg/errors"
)

func main() {
	l := &retry.Retry{
		Attempts: 4,
		Delay:    time.Nanosecond,
	}
	i := 0
	err := l.Do(func() error {
		i++
		fmt.Printf("Running iteration %d.\n", i)
		if i < 3 {
			return errors.New("ignored error")
		}
		return nil
	})
	fmt.Println("Error:", err)

}
Output:

Running iteration 1.
Running iteration 2.
Running iteration 3.
Error: <nil>
Example (Stop)
package main

import (
	"fmt"

	"github.com/arsham/retry"
	"github.com/pkg/errors"
)

func main() {
	l := &retry.Retry{
		Attempts: 10,
	}
	i := 0
	err := l.Do(func() error {
		i++
		fmt.Printf("Running iteration %d.\n", i)
		if i > 2 {
			return retry.StopError{}
		}
		return errors.New("ignored error")
	})
	fmt.Println("Error:", err)

}
Output:

Running iteration 1.
Running iteration 2.
Running iteration 3.
Error: <nil>
Example (StopErr)
package main

import (
	"fmt"

	"github.com/arsham/retry"
	"github.com/pkg/errors"
)

func main() {
	l := &retry.Retry{
		Attempts: 10,
	}
	i := 0
	stopErr := &retry.StopError{
		Err: errors.New("this is the returned error"),
	}
	err := l.Do(func() error {
		i++
		if i > 2 {
			return stopErr
		}
		return errors.New("ignored error")
	})
	fmt.Println("Error:", err)
	fmt.Println("Stopped with:", stopErr)

}
Output:

Error: this is the returned error
Stopped with: this is the returned error
Example (Zero)
package main

import (
	"fmt"

	"github.com/arsham/retry"
)

func main() {
	l := &retry.Retry{}
	err := l.Do(func() error {
		fmt.Println("this should not happen")
		return nil
	})
	fmt.Println("Error:", err)

}
Output:

Error: <nil>

type StopError

type StopError struct {
	Err error
}

StopError causes the Do method stop trying and will return the Err.

func (StopError) Error

func (s StopError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL