Files
overnight-trading-bot/internal/tinvest/retry.go
T
2026-06-08 09:41:20 +00:00

89 lines
1.7 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() (T, error)) (T, error) {
if timeout <= 0 {
return fn()
}
callCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
type result struct {
value T
err error
}
done := make(chan result, 1)
go func() {
value, err := fn()
done <- result{value: value, err: err}
}()
select {
case res := <-done:
return res.value, res.err
case <-callCtx.Done():
var zero T
return zero, callCtx.Err()
}
}