Skip to content

Instantly share code, notes, and snippets.

@williammartin
Created May 12, 2022 13:48
Show Gist options
  • Save williammartin/6929174cc4559ea53b4c1b64d2cdb57b to your computer and use it in GitHub Desktop.
Save williammartin/6929174cc4559ea53b4c1b64d2cdb57b to your computer and use it in GitHub Desktop.
package retry
import (
"context"
"errors"
"fmt"
"math"
"time"
)
type DelayFunc func(attempt uint8) time.Duration
type Config struct {
limit uint8
delayFunc DelayFunc
ctx context.Context
}
type RetryOption func(*Config)
type Retryable func() error
type irrecoverable interface {
Irrecoverable() bool
}
func IsIrrecoverable(err error) bool {
var te irrecoverable
ok := errors.As(err, &te)
return ok && te.Irrecoverable()
}
func Do(retryable Retryable, opts ...RetryOption) error {
const defaultLimit uint8 = 3
config := &Config{
limit: defaultLimit,
delayFunc: func(attempt uint8) time.Duration {
return 0
},
ctx: context.Background(),
}
for _, opt := range opts {
opt(config)
}
attempts := uint8(0)
for {
err := retryable()
if err == nil {
return nil
}
if IsIrrecoverable(err) {
return err
}
attempts++
if attempts >= config.limit {
return err
}
select {
case <-config.ctx.Done():
return fmt.Errorf("context cancelled")
case <-time.After(config.delayFunc(attempts)):
// Do nothing intentionally
}
}
}
func WithRetryLimit(limit uint8) RetryOption {
return func(config *Config) {
config.limit = limit
}
}
func WithDelayFunc(delayFunc DelayFunc) RetryOption {
return func(config *Config) {
config.delayFunc = delayFunc
}
}
func FixedDelay(delay time.Duration) DelayFunc {
return func(attempt uint8) time.Duration {
return delay
}
}
func ExponentialDelay(delay time.Duration) DelayFunc {
const exponent = 2
return func(attempt uint8) time.Duration {
return time.Duration(float64(delay) * math.Pow(exponent, float64(attempt-1)))
}
}
func WithContext(ctx context.Context) RetryOption {
return func(config *Config) {
config.ctx = ctx
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment