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 };
}