retry

package module
v0.0.0-...-86c8baa Latest Latest
Warning

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

Go to latest
Published: Jan 23, 2020 License: MIT Imports: 4 Imported by: 1

README

Retry Build Status Go Report Card GoDoc Coverage Status

Lego Batman gif retry

Retry is a Go package which wraps a function and invokes it repeatedly, until it succeeds - not returning an error. Multiple retry-able options are provided, based on number of attempts, delay options between attempts, errors to retry on or ignore, post attempts callback etc. Usable for interaction with flaky web services and similar unreliable sources of frustration.

Installation

go get -u github.com/adamliesko/retry

Usage

In the simplest and default configuration only about calling package level function Do(), with the desired function. If the failed function fails after 10 retries a custom error of Max Attempts reached is returned. An alternative is using a reusable Retryer value struct (=instance in OOP), which will be reset after each Do() method call.


import "external"

func poll() error{
    return external.IsItDone() 
}
    
// equivalent calls
err1 := retry.Do(poll)
err2 := retry.New().Do(poll)
r := retry.New()
err3 := r.Do(poll)

The usual usage would be to use either directly function, which returns an error or wrap the function call with a function, which sets the error according to the inner function output.

// can be used directly
func poll() error{
    return external.IsItDone() 
}

// has to be wrapped
func pollNoError bool{
    return external.HasItSucceeded()
}

func wrappedPoll() error{
    if !pollNoError(){
        return errors.New("pollNoError has failed")
    }
    return nil
}

result := retry.Do(wrappedPoll)
Options on Retryer (listed below in greater detail):
  • constant sleep delay after a failure
  • custom function sleep delay (e.g. exponential back off)
  • recovery of panics
  • calling ensure function, regardless of the Retryer's work inside, once that it finishes
  • calling a custom function after each failure
  • ignoring certain errors
  • retrying only on certain errors
Constant delay of of 100ms between failing attempts
func poll() error { return external.IsItDone() }
    
err := retry.New(retry.Sleep(100))
result := r.Do(poll)
Using an exponential back off (or any other custom function) after each failed attempt
func poll() error { return external.IsItDone() }
        
sleepFn := func(attempts int) {
    sleep := time.Duration(2^attempts) * time.Millisecond
    time.Sleep(sleep)
}

err := retry.New(retry.SleepFn(sleepFn)).Do(poll)
Calling an ensure function, which is called after whole Retryer execution
func poll() error { return external.IsItDone() }
        
func ensure(err error){
    fmt.Println("ensure will be called regardless of err value")
}

err := retry.Do(poll, retry.Ensure(ensure))
Ignoring failures with errors of listed types (whitelist) and considering them as success
type MyError struct {}

func (e MyError) Error() string { return "this is my custom error" }
	
func poll() error { return external.IsItDone() }
        
err := retry.New(Not([]errors{MyError{}})).Do(poll)
Retrying only on listed error types (blacklist), other errors will be considered as success
type MyError struct {}

func (e MyError) Error() string { return "this is my custom error" }

func poll() error { return external.IsItDone() }
        
err := retry.New(On([]errors{MyError{}})).Do(poll)
Retry allows to combine many options in one Retryer. The code block below will enable:
  • recovery of panics
  • attempting to call the function up to 15 times
  • sleeping for 200 ms after each failed attempt
  • printing the failures to the Stdout
func poll() error { return external.IsItDone() }
     
failCallback := func(err error){ fmt.Println("failed with error", error) }

r := retry.New(retry.Sleep(200), retry.Tries(15), retry.Recover(), retry.AfterEachFail(failCallback)
err := r.Do(poll)

License

See LICENSE.

Documentation

Overview

Package retry provides a configurable construct to retry execution of flaky function calls. Retryer can repeatedly invoke function call, till it succeeds.

Index

Constants

View Source
const MaxRetries = 10

MaxRetries is the maximum number of retries.

Variables

This section is empty.

Functions

func AfterEachFail

func AfterEachFail(failFn func(error)) func(*Retryer)

AfterEachFail configures the Retryer to call failFn function after each of the failed attempts.

func Do

func Do(fn func() error, opts ...func(*Retryer)) error

Do is wrapper around Retryer, which doesn't expose the Retryer itself, only calls the function until it succeeds.

func Ensure

func Ensure(ensureFn func(error)) func(*Retryer)

Ensure sets a deferred function to be called, regardless of Retryer succeeding in running the function with or without an error.

func Not

func Not(errors []error) func(*Retryer)

Not configures the Retryer to ignore all of the passed in errors and in case of them appearing doesn't retry function anymore.

func On

func On(errors []error) func(r *Retryer)

On configures the Retryer to retry function call on any of the passed in errors.

func Recover

func Recover() func(*Retryer)

Recover configures the Retryer to recover panics, returning an error containing the panic and it's stacktrace.

func Sleep

func Sleep(dur int) func(*Retryer)

Sleep configures the Retryer to sleep and delay the next execution of a function for certain duration [ms] after each failed attempt.

func SleepFn

func SleepFn(sleepFn func(int)) func(*Retryer)

SleepFn configures the Retryer to call a custom, caller supplied function after each failed attempt. SleepFn takes precedence over a set sleep duration.

func Tries

func Tries(tries int) func(r *Retryer)

Tries configures to Retryer to keep calling the function until it succeeds tries-times. If 0 is supplied, Retryer will call the function until it succeeds, regardless of number of tries.

Types

type Retryer

type Retryer struct {
	Tries    int
	On       []error       // On is the slice of errors, on which Retryer will retry a function
	Not      []error       // Not is the slice of errors which Retryer won't consider as needed to retry
	SleepDur time.Duration // Sleep duration in ms
	Recover  bool          // If enabled, panics will be recovered.

	SleepFn         func(int)   // Custom sleep function with access to the current # of attempts
	EnsureFn        func(error) // DeferredFn is called after repeated function finishes, regardless of outcome
	AfterEachFailFn func(error) // Callback called after each of the failures (for example some logging)
	// contains filtered or unexported fields
}

Retryer is configurable runner, which repeats function calls until it succeeds.

func New

func New(opts ...func(*Retryer)) *Retryer

New creates a Retryer with applied options.

func (*Retryer) Attempts

func (r *Retryer) Attempts() int

Attempts return the number of times Retryer has invoked a function call.

func (*Retryer) Do

func (r *Retryer) Do(fn func() error) (err error)

Do calls the passed in function until it succeeds. The behaviour of the retry mechanism heavily relies on the config of the Retryer.

func (*Retryer) Reset

func (r *Retryer) Reset()

Reset resets the state of the Retryer to the default starting one, resetting the number of attempts to 0.

Jump to

Keyboard shortcuts

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