Throttling
using System;
using System.Collections.Generic;
using System.Threading;
/// <summary>A class to manage operations over time</summary>
public sealed class TimeThrottler
{
#region Class members
/// <summary>list of datetimes for throttled operations</summary>
private readonly IList<DateTime> lastOperations = new List<DateTime>();
/// <summary>The of operations allowed within a single throttled time period</summary>
private int operationLimit;
/// <summary>The time period in which operations are limited</summary>
private TimeSpan timePeriod;
#endregion
/// <summary>Initializes a new instance of the <see cref="TimeThrottler"/> class.</summary>
/// <param name="timePeriod">The time period.</param>
/// <param name="operationLimit">The operation limit.</param>
public TimeThrottler(TimeSpan timePeriod, int operationLimit)
{
this.TimePeriod = timePeriod;
this.OperationLimit = operationLimit;
}
#region Class Properties
/// <summary>Gets or sets the operation limit.</summary>
/// <value>The operation limit.</value>
public int OperationLimit
{
get
{
return this.operationLimit;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("OperationLimit", "OperationLimit must be greater than zero");
}
this.operationLimit = value;
}
}
/// <summary>Gets or sets the time period.</summary>
/// <value>The time period.</value>
public TimeSpan TimePeriod
{
get
{
return this.timePeriod;
}
set
{
this.timePeriod = value;
}
}
#endregion
/// <summary>Throttles execution on the basis of previous operations and limits.</summary>
public void Throttle()
{
if (this.timePeriod != TimeSpan.Zero)
{
if (this.lastOperations.Count > 0)
{
int i;
DateTime utcNow = DateTime.UtcNow;
DateTime cutOff = utcNow.Subtract(this.timePeriod);
DateTime oldestOperation = DateTime.MaxValue;
int operationCount = 0;
// Process existing operations
for (i = 0; i < this.lastOperations.Count; i++)
{
// Prune expired operations
if (this.lastOperations[i] <= cutOff)
{
this.lastOperations.RemoveAt(i);
i--;
}
else
{
// Increment operation count; set the oldest valid operation
operationCount++;
if (this.lastOperations[i] < oldestOperation)
{
oldestOperation = this.lastOperations[i];
}
}
}
if (operationCount > 0)
{
// Decide whether to 'throttle' (sleep) this call until limit elapses for oldest call
if (operationCount >= this.operationLimit)
{
TimeSpan timeout = oldestOperation.Add(this.timePeriod).Subtract(utcNow);
if (timeout != TimeSpan.Zero)
{
Thread.Sleep(timeout);
}
}
}
}
// Add the current operation
this.lastOperations.Add(DateTime.UtcNow);
}
}
}
page revision: 1, last edited: 17 Dec 2008 11:37