yavsc/Yavsc/GoogleApiSupport/Google.Apis.Core/Util/ExponentialBackOff.cs

100 lines
3.8 KiB
C#

/*
Copyright 2013 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
namespace Google.Apis.Util
{
/// <summary>
/// Implementation of <see cref="IBackOff"/> that increases the back-off period for each retry attempt using a
/// randomization function that grows exponentially. In addition, it also adds a randomize number of milliseconds
/// for each attempt.
/// </summary>
public class ExponentialBackOff : IBackOff
{
/// <summary>The maximum allowed number of retries.</summary>
private const int MaxAllowedNumRetries = 20;
private readonly TimeSpan deltaBackOff;
/// <summary>
/// Gets the delta time span used to generate a random milliseconds to add to the next back-off.
/// If the value is <see cref="System.TimeSpan.Zero"/> then the generated back-off will be exactly 1, 2, 4,
/// 8, 16, etc. seconds. A valid value is between zero and one second. The default value is 250ms, which means
/// that the generated back-off will be [0.75-1.25]sec, [1.75-2.25]sec, [3.75-4.25]sec, and so on.
/// </summary>
public TimeSpan DeltaBackOff
{
get { return deltaBackOff; }
}
private readonly int maxNumOfRetries;
/// <summary>Gets the maximum number of retries. Default value is <c>10</c>.</summary>
public int MaxNumOfRetries
{
get { return maxNumOfRetries; }
}
/// <summary>The random instance which generates a random number to add the to next back-off.</summary>
private Random random = new Random();
/// <summary>Constructs a new exponential back-off with default values.</summary>
public ExponentialBackOff()
: this(TimeSpan.FromMilliseconds(250))
{
}
/// <summary>Constructs a new exponential back-off with the given delta and maximum retries.</summary>
public ExponentialBackOff(TimeSpan deltaBackOff, int maximumNumOfRetries = 10)
{
if (deltaBackOff < TimeSpan.Zero || deltaBackOff > TimeSpan.FromSeconds(1))
{
throw new ArgumentOutOfRangeException("deltaBackOff");
}
if (maximumNumOfRetries < 0 || maximumNumOfRetries > MaxAllowedNumRetries)
{
throw new ArgumentOutOfRangeException("deltaBackOff");
}
this.deltaBackOff = deltaBackOff;
this.maxNumOfRetries = maximumNumOfRetries;
}
#region IBackOff Members
/// <inheritdoc/>
public TimeSpan GetNextBackOff(int currentRetry)
{
if (currentRetry <= 0)
{
throw new ArgumentOutOfRangeException("currentRetry");
}
if (currentRetry > MaxNumOfRetries)
{
return TimeSpan.MinValue;
}
// Generate a random number of milliseconds and add it to the current exponential number.
var randomMilli = (double)random.Next(
(int)(DeltaBackOff.TotalMilliseconds * -1),
(int)(DeltaBackOff.TotalMilliseconds * 1));
int backOffMilli = (int)(Math.Pow(2.0, (double)currentRetry - 1) * 1000 + randomMilli);
return TimeSpan.FromMilliseconds(backOffMilli);
}
#endregion
}
}