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);
            }
        }
    }
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License