// Package utils provides shared utilities for the fetch_ml project. package network import ( "context" "math" "time" ) type RetryConfig struct { MaxAttempts int InitialDelay time.Duration MaxDelay time.Duration Multiplier float64 } func DefaultRetryConfig() RetryConfig { return RetryConfig{ MaxAttempts: 3, InitialDelay: 1 * time.Second, MaxDelay: 30 * time.Second, Multiplier: 2.0, } } func Retry(ctx context.Context, cfg RetryConfig, fn func() error) error { var lastErr error delay := cfg.InitialDelay for attempt := 0; attempt < cfg.MaxAttempts; attempt++ { if err := fn(); err == nil { return nil } else { lastErr = err } if attempt < cfg.MaxAttempts-1 { select { case <-ctx.Done(): return ctx.Err() case <-time.After(delay): delay = time.Duration(math.Min( float64(delay)*cfg.Multiplier, float64(cfg.MaxDelay), )) } } } return lastErr } // RetryWithBackoff provides a convenient wrapper for common retry scenarios func RetryWithBackoff(ctx context.Context, maxAttempts int, operation func() error) error { cfg := RetryConfig{ MaxAttempts: maxAttempts, InitialDelay: 200 * time.Millisecond, MaxDelay: 2 * time.Second, Multiplier: 2.0, } return Retry(ctx, cfg, operation) } // RetryForNetworkOperations is optimized for network-related operations func RetryForNetworkOperations(ctx context.Context, operation func() error) error { cfg := RetryConfig{ MaxAttempts: 5, InitialDelay: 200 * time.Millisecond, MaxDelay: 5 * time.Second, Multiplier: 1.5, } return Retry(ctx, cfg, operation) }