<commit_before># retry
[![Build Status](https://secure.travis-ci.org/adamliesko/retry.svg)](http://travis-ci.org/adamliesko/retry)
[![Go Report Card](https://goreportcard.com/badge/github.com/adamliesko/retry)](https://goreportcard.com/report/github.com/adamliesko/retry)
[![GoDoc](https://godoc.org/github.com/adamliesko/retry?status.svg)](https://godoc.org/github.com/adamliesko/retry)
[![Coverage Status](https://img.shields.io/coveralls/adamliesko/retry.svg)](https://coveralls.io/r/adamliesko/retry?branch=master)

Retry is a Go package which wraps a function and retries it until it succeeds, not returning na error. Multiple retry-able
options are provided, based on number of attempts, sleep after failed attempt, errors to retry on or skip, post attempts
callback etc. Usable for interaction with flake-y web services and similar unreliable sources of frustration.

## Installation

```
go get -u github.com/adamliesko/retry
```

## Usage

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

```go
// 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 nil
	}
	
	return errors.New("pollNoError has failed")
}
```

In the simplest and default configuration, with 10 retries it's only about creating a new Retryer and calling Do, with
the desired function. If the failed functions failes after 10 retries a custom error of Max Attempts reached is returned.
Befor each call of Retryer's Do() it's state is reset, which makes the Retryer reusable.
```go
func poll() error{
    return external.IsItDone() 
}
    
result := retry.New().Do(poll)
```

Options on Retryer (listed below in greater detail):
- constant sleep delay after a failure
- custom function sleep delay (e.g. exponential backoff)
- recovery of panics
- calling an 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

#### Sleeping constant duration of 100ms after each failed attempt
```go
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
```go
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
```go
func poll() error {
    return external.IsItDone()
}
        
func ensure(err error){
	fmt.Println("ensure will be called regardless of err value")
}

err := retry.New(retry.Ensure(ensure)).Do(poll)
```

#### Ignoring failures with errors of listed types (whitelist)
```go
func poll() error {
    return external.IsItDone()
}
        
err := retry.New(Not([]errors{})).Do(poll)
```

#### Retrying only on listed error types (blacklist)
```go
func poll() error {
    return external.IsItDone()
}
        
err := retry.New(On([]errors{})).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

```go
func poll() error {<commit_msg>More coincise README - order for the 1st time reader<commit_after># retry
![Build Status](https://secure.travis-ci.org/adamliesko/retry.svg)
![Go Report Card](https://goreportcard.com/badge/github.com/adamliesko/retry)
![GoDoc](https://godoc.org/github.com/adamliesko/retry?status.svg)
![Coverage Status](https://img.shields.io/coveralls/adamliesko/retry.svg)

Retry is a Go package which wraps a function and retries it until it succeeds, not returning na error. Multiple retry-able
options are provided, based on number of attempts, sleep after failed attempt, errors to retry on or skip, post attempts
callback etc. Usable for interaction with flake-y web services and similar unreliable sources of frustration.

![Lego Batman gif retry](https://media.giphy.com/media/JJhiRdcYfcokU/giphy.gif)
## Installation

```
go get -u github.com/adamliesko/retry
```

## Usage

In the simplest and default configuration, with 10 retries it's only about creating a new Retryer and calling Do, with
the desired function. If the failed functions failes after 10 retries a custom error of Max Attempts reached is returned.
Befor each call of Retryer's Do() it's state is reset, which makes the Retryer reusable.
```go
func poll() error{
    return external.IsItDone() 
}
    
result := retry.New().Do(poll)
```

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

```go
// 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 nil
	}
	
	return errors.New("pollNoError has failed")
}
```

Options on Retryer (listed below in greater detail):
- constant sleep delay after a failure
- custom function sleep delay (e.g. exponential backoff)
- recovery of panics
- calling an 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

#### Sleeping constant duration of 100ms after each failed attempt
```go
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
```go
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
```go
func poll() error {
    return external.IsItDone()
}
        
func ensure(err error){
	fmt.Println("ensure will be called regardless of err value")
}

err := retry.New(retry.Ensure(ensure)).Do(poll)
```

#### Ignoring failures with errors of listed types (whitelist) and considering them as success
```go
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
```go
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

```go
func poll() error {
{'fraction_non_alphanumeric': 0.10951430472388556, 'fraction_numerical': 0.004391217564870259, 'mean_word_length': 4.219444444444444, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '997918', 'n_tokens_mistral': 2320, 'n_tokens_neox': 2221, 'n_words': 860}