74 lines
1.5 KiB
Go
74 lines
1.5 KiB
Go
package tinvest
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
backofflib "github.com/cenkalti/backoff/v4"
|
|
)
|
|
|
|
func withRetry(ctx context.Context, attempts int, interval time.Duration, fn func() error) error {
|
|
if attempts <= 0 {
|
|
attempts = 1
|
|
}
|
|
if interval < 0 {
|
|
interval = 0
|
|
}
|
|
policy := backofflib.NewExponentialBackOff()
|
|
policy.InitialInterval = interval
|
|
policy.MaxInterval = interval * 8
|
|
policy.Multiplier = 2
|
|
policy.MaxElapsedTime = 0
|
|
policy.Reset()
|
|
var lastErr error
|
|
for attempt := 0; attempt < attempts; attempt++ {
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
if err := fn(); err != nil {
|
|
lastErr = err
|
|
} else {
|
|
return nil
|
|
}
|
|
if attempt == attempts-1 || interval <= 0 {
|
|
continue
|
|
}
|
|
timer := time.NewTimer(policy.NextBackOff())
|
|
select {
|
|
case <-timer.C:
|
|
case <-ctx.Done():
|
|
if !timer.Stop() {
|
|
select {
|
|
case <-timer.C:
|
|
default:
|
|
}
|
|
}
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
return lastErr
|
|
}
|
|
|
|
func retryValue[T any](ctx context.Context, attempts int, interval time.Duration, fn func() (T, error)) (T, error) {
|
|
var out T
|
|
err := withRetry(ctx, attempts, interval, func() error {
|
|
var err error
|
|
out, err = fn()
|
|
return err
|
|
})
|
|
if err != nil {
|
|
var zero T
|
|
return zero, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func requestWithTimeout[T any](ctx context.Context, timeout time.Duration, fn func(context.Context) (T, error)) (T, error) {
|
|
if timeout <= 0 {
|
|
return fn(ctx)
|
|
}
|
|
callCtx, cancel := context.WithTimeout(ctx, timeout)
|
|
defer cancel()
|
|
return fn(callCtx)
|
|
}
|