# GoRetry

The GoRetry library manages retry and timeout logic in your Fulton project, so you don't have to!

Builds off of the retry-go library, available on [Github][1].

## Features

- Handles retryable error codes for Twirp and AWS SDK.
- Allows for per-operation timeouts and retry attempts (AWS SDK only allows configuration at the client level).
- Handles context-based timeouts internally, reducing the risk of incorrect timeout handling implementations.
- Allows for use of fixed or exponential timeouts.
- Adds jitter to retries, improving the reliability of distributed system requests and reducing the risk of thundering herd scenarios.

## Usage

### Setup

Import this library in your Brazil config:

```
dependencies = {
    1.0 = {
        ...
        GoRetry = 1.0;
        ...
    };
};
```

### AWS SDK Prerequisites

Each [AWS SDK][2] performs its own retry logic. This must be disabled before using this library to prevent excessive retries.

When creating an AWS SDK client, you should update the session configuration for every AWS SDK client to disable retries:

```
import "github.com/aws/aws-sdk-go/aws"
...
awsConfig := aws.NewConfig().WithRegion(RegionKey).WithMaxRetries(0)
session, err := session.NewSession(awsConfig)
```

### Basic Usage

```
func retry.RetryFuncWithContext(ctx, RetryableFunc, Options) error
func retry.RetryFunc(RetryableFunc, Options) error
```

The GoRetry library takes the following parameters:
- Context (if using `RetryFuncWithContext`).
- A retryable function in the form:

    `func(ctx context.Context) (err error)`

    _If your function implements any blocking commands that do not implement context cancellation, use `RetryFunc` instead._

- An `Options` object (optionally) containing a timeout value and logger.

    | Property            | Description                                                     | Default Value |
    | ------------------- | --------------------------------------------------------------- | ------------- |
    | `Timeout`           | The operation timeout.                                          | 10sec         |
    | `TimeoutMax`        | The maximum operation timeout, if using `Exponential` timeouts. |               |
    | `TimeoutType`       | The type of timeout, either `Fixed` or `Exponential`.           | `Fixed`       |
    | `MaxAttempts`       | The maximum number of times to attempt `RetryableFunc`.         | 3             |
    | `InitialRetryDelay` | The initial retry delay - exponential backoff by default.       | 10ms          |
    | `Logger`            | The logger to record any errors in `RetryableFunc`.             |               |

#### Example

```
err = retry.RetryFunc(
	ctx,
	func(ctx context.Context) (err error) {
		_, err = FlakyFunction(ctx)
		return
	},
	retry.Options{Timeout: TimeoutValue, Logger: Logger},
)
```

### Retrying Functions with Return Values

Values can be returned from retryable functions by declaring return variables above the retry block:

```
var response ResponseObject
err := retry.RetryFunc(
	ctx,
	func(ctx context.Context) (err error) {
		response, err = FlakyFunction(ctx)
		return
	},
	retry.Options{Timeout: TimeoutValue, Logger: Logger},
)
```

## Contributions

Have a suggestion on how to improve GoRetry? Feel free to submit a CR! All published CRs will notify _#the-rock-crs_ on Twitch Slack.

## Questions?

Reach out to the [_#GoRetry_](https://twitch.slack.com/archives/C021N1XLDA8) channel on Twitch Slack!

If you're not a Twitch employee, reach out to [the-rock-eng@twitch.tv](mailto:the-rock-eng@twitch.tv).

 [1]: https://github.com/avast/retry-go
 [2]: https://docs.aws.amazon.com/general/latest/gr/api-retries.html
