You've already forked linux-packaging-mono
137 lines
6.1 KiB
C#
137 lines
6.1 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
namespace System.Data.Entity.Infrastructure
|
|
{
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity.Resources;
|
|
using System.Linq;
|
|
|
|
/// <summary>
|
|
/// A retry policy with exponentially increasing delay between retries.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The following formula is used to calculate the delay after <c>retryCount</c> number of attempts:
|
|
/// <code>min(minDelay + coefficient * random(1, maxRandomFactor) * (exponentialBase ^ retryCount - 1), maxDelay)</code>
|
|
/// The <c>retryCount</c> starts at 0.
|
|
/// The <c>random</c> factor distributes uniformly the retry attempts from multiple parallel actions failing simultaneously.
|
|
/// The <c>coefficient</c> determines the scale at wich the delay is increased while the <c>exponentialBase</c>
|
|
/// sets the speed of the delay increase.
|
|
/// </remarks>
|
|
public class ExponentialRetryDelayStrategy : IRetryDelayStrategy
|
|
{
|
|
private readonly int _maxRetryCount;
|
|
private readonly TimeSpan _minDelay;
|
|
private readonly TimeSpan _maxDelay;
|
|
private readonly double _maxRandomFactor;
|
|
private readonly double _exponentialBase;
|
|
private readonly TimeSpan _coefficient;
|
|
|
|
/// <summary>
|
|
/// The default number of retry attempts.
|
|
/// </summary>
|
|
public static readonly int DefaultMaxRetryCount = 5;
|
|
|
|
/// <summary>
|
|
/// The default maximum random factor.
|
|
/// </summary>
|
|
public static readonly double DefaultRandomFactor = 1.1;
|
|
|
|
/// <summary>
|
|
/// The default base for the exponential function used to compute the delay between retries.
|
|
/// </summary>
|
|
public static readonly double DefaultExponentialBase = 2;
|
|
|
|
/// <summary>
|
|
/// The default coefficient for the exponential function used to compute the delay between retries.
|
|
/// </summary>
|
|
public static readonly TimeSpan DefaultCoefficient = TimeSpan.FromSeconds(1);
|
|
|
|
/// <summary>
|
|
/// The default maximum time delay between retries.
|
|
/// </summary>
|
|
public static readonly TimeSpan DefaultMaxDelay = TimeSpan.FromSeconds(30);
|
|
|
|
/// <summary>
|
|
/// The default minimum time delay between retries.
|
|
/// </summary>
|
|
public static readonly TimeSpan DefaultMinDelay = TimeSpan.FromSeconds(0);
|
|
|
|
private readonly List<Exception> _exceptionsEncountered = new List<Exception>();
|
|
private readonly Random _random = new Random();
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ExponentialRetryDelayStrategy"/> class.
|
|
/// </summary>
|
|
public ExponentialRetryDelayStrategy()
|
|
: this(DefaultMaxRetryCount, DefaultMinDelay, DefaultMaxDelay, DefaultRandomFactor, DefaultExponentialBase, DefaultCoefficient)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ExponentialRetryDelayStrategy"/> class.
|
|
/// </summary>
|
|
/// <param name="maxRetryCount"> The maximum number of retry attempts. </param>
|
|
/// <param name="minDelay"> The minimum delay in milliseconds between retries, must be nonnegative. </param>
|
|
/// <param name="maxDelay"> The maximum delay in milliseconds between retries, must be equal or greater than <paramref name="minDelay"/>. </param>
|
|
/// <param name="maxRandomFactor"> The maximum random factor, must not be lesser than 1. </param>
|
|
/// <param name="exponentialBase"> The base for the exponential function used to compute the delay between retries, must be positive. </param>
|
|
/// <param name="coefficient"> The coefficient for the exponential function used to compute the delay between retries, must be nonnegative. </param>
|
|
public ExponentialRetryDelayStrategy(
|
|
int maxRetryCount, TimeSpan minDelay, TimeSpan maxDelay, double maxRandomFactor, double exponentialBase, TimeSpan coefficient)
|
|
{
|
|
if (maxRetryCount < 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("maxRetryCount");
|
|
}
|
|
if (minDelay.TotalMilliseconds < 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("minDelay");
|
|
}
|
|
if (minDelay.TotalMilliseconds > maxDelay.TotalMilliseconds)
|
|
{
|
|
throw new ArgumentOutOfRangeException("maxDelay", Strings.ExecutionStrategy_MinimumMustBeLessThanMaximum);
|
|
}
|
|
if (maxRandomFactor < 1.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("maxRandomFactor");
|
|
}
|
|
if (exponentialBase <= 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("exponentialBase");
|
|
}
|
|
if (coefficient.TotalMilliseconds < 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("coefficient");
|
|
}
|
|
|
|
_maxRetryCount = maxRetryCount;
|
|
_minDelay = minDelay;
|
|
_maxDelay = maxDelay;
|
|
_maxRandomFactor = maxRandomFactor;
|
|
_exponentialBase = exponentialBase;
|
|
_coefficient = coefficient;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public TimeSpan? GetNextDelay(Exception lastException)
|
|
{
|
|
_exceptionsEncountered.Add(lastException);
|
|
|
|
var currentRetryCount = _exceptionsEncountered.Count() - 1;
|
|
if (currentRetryCount < _maxRetryCount)
|
|
{
|
|
var delta = (Math.Pow(_exponentialBase, currentRetryCount) - 1.0)
|
|
* (1.0 + _random.NextDouble() * (_maxRandomFactor - 1.0));
|
|
|
|
var delay = Math.Min(
|
|
_minDelay.TotalMilliseconds + _coefficient.TotalMilliseconds * delta,
|
|
_maxDelay.TotalMilliseconds);
|
|
|
|
return TimeSpan.FromMilliseconds(delay);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|