func Tick(tick time.Duration) BackoffStrategy {
	return func(last time.Duration) time.Duration {
		return tick
	}
}
Tick keeps a constant backoff interval
package retry
import (
	"context"
	"errors"
	"time"
)
type RetriableErr struct {
	error
}
func Retriable(err error) *RetriableErr {
	return &RetriableErr{err}
}
type Retry struct {
	backoff BackoffStrategy
	base    time.Duration
}
var r = New()
func (r *Retry) Ensure(ctx context.Context, do func() error) error {
	duration := r.base
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}
		if err := do(); err != nil {
			if _, ok := err.(*RetriableErr); ok {
				if r.backoff != nil {
					duration = r.backoff(duration)
					time.Sleep(duration)
				}
				continue
			}
			return err
		}
		return nil
	}
}
func (r *Retry) EnsureN(ctx context.Context, N int, do func() error) error {
	count := 0
	return r.Ensure(ctx, func() error {
		if count >= N {
			return errors.New("retry limit exceed")
		}
		count++
		return do()
	})
}
type Option func(r *Retry)
type BackoffStrategy func(last time.Duration) time.Duration
func WithBackoff(backoff BackoffStrategy) Option {
	return func(r *Retry) {
		r.backoff = backoff
	}
}
func WithBaseDelay(base time.Duration) Option {
	return func(r *Retry) {
		r.base = base
	}
}
func New(opts ...Option) *Retry {
	r := &Retry{base: 10 * time.Millisecond, backoff: Exponential(2)}
	for _, opt := range opts {
		opt(r)
	}
	return r
}
func Exponential(factor float64) BackoffStrategy {
	return func(last time.Duration) time.Duration {
		return time.Duration(float64(last) * factor)
	}
}