// Package network provides SSH client and retry utilities. package network import ( "context" "math" "time" ) // RetryConfig defines retry behavior parameters. type RetryConfig struct { MaxAttempts int InitialDelay time.Duration MaxDelay time.Duration Multiplier float64 } // DefaultRetryConfig returns a default retry configuration. func DefaultRetryConfig() RetryConfig { return RetryConfig{ MaxAttempts: 3, InitialDelay: 1 * time.Second, MaxDelay: 30 * time.Second, Multiplier: 2.0, } } // Retry executes a function with exponential backoff retry logic. func Retry(ctx context.Context, cfg RetryConfig, fn func() error) error { var lastErr error delay := cfg.InitialDelay for attempt := 0; attempt < cfg.MaxAttempts; attempt++ { err := fn() if err == nil { return nil } 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) }