using System; namespace Wino.Core.Domain.Models.Retry; /// /// Defines retry behavior for synchronization operations with exponential backoff. /// public class RetryPolicy { private static readonly Random _jitterRandom = new(); /// /// Gets or sets the maximum number of retry attempts. Default is 3. /// public int MaxRetries { get; set; } = 3; /// /// Gets or sets the initial delay before the first retry. Default is 1 second. /// public TimeSpan InitialDelay { get; set; } = TimeSpan.FromSeconds(1); /// /// Gets or sets the multiplier for exponential backoff. Default is 2.0. /// Each retry delay = previous delay * multiplier. /// public double BackoffMultiplier { get; set; } = 2.0; /// /// Gets or sets the maximum delay between retries. Default is 2 minutes. /// public TimeSpan MaxDelay { get; set; } = TimeSpan.FromMinutes(2); /// /// Gets or sets whether to add random jitter to delays to prevent thundering herd. /// Default is true. /// public bool UseJitter { get; set; } = true; /// /// Gets or sets the maximum jitter as a percentage of the delay (0.0 to 1.0). /// Default is 0.25 (25%). /// public double JitterFactor { get; set; } = 0.25; /// /// Calculates the delay for the given retry attempt using exponential backoff. /// /// The retry attempt number (1-based). /// The delay to wait before the retry. public TimeSpan GetDelay(int retryAttempt) { if (retryAttempt <= 0) return TimeSpan.Zero; // Calculate base delay with exponential backoff var baseDelayMs = InitialDelay.TotalMilliseconds * Math.Pow(BackoffMultiplier, retryAttempt - 1); // Apply max delay cap baseDelayMs = Math.Min(baseDelayMs, MaxDelay.TotalMilliseconds); // Apply jitter if enabled if (UseJitter) { var jitterRange = baseDelayMs * JitterFactor; var jitter = (_jitterRandom.NextDouble() * 2 - 1) * jitterRange; // +/- jitter range baseDelayMs = Math.Max(0, baseDelayMs + jitter); } return TimeSpan.FromMilliseconds(baseDelayMs); } /// /// Creates a default retry policy suitable for most synchronization operations. /// public static RetryPolicy Default => new(); /// /// Creates an aggressive retry policy with more attempts and shorter delays. /// Suitable for transient network issues. /// public static RetryPolicy Aggressive => new() { MaxRetries = 5, InitialDelay = TimeSpan.FromMilliseconds(500), BackoffMultiplier = 1.5, MaxDelay = TimeSpan.FromSeconds(30) }; /// /// Creates a conservative retry policy with longer delays. /// Suitable for rate limiting scenarios. /// public static RetryPolicy RateLimited => new() { MaxRetries = 3, InitialDelay = TimeSpan.FromSeconds(10), BackoffMultiplier = 2.0, MaxDelay = TimeSpan.FromMinutes(5) }; /// /// Creates a no-retry policy that doesn't retry on failure. /// public static RetryPolicy NoRetry => new() { MaxRetries = 0 }; }