File: System\Threading\RateLimiting\RateLimitPartition.cs
Web Access
Project: src\src\libraries\System.Threading.RateLimiting\src\System.Threading.RateLimiting.csproj (System.Threading.RateLimiting)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace System.Threading.RateLimiting
{
    /// <summary>
    /// Contains methods used in <see cref="PartitionedRateLimiter.Create"/> to assist in the creation of partitions for your rate limiter.
    /// </summary>
    public static class RateLimitPartition
    {
        /// <summary>
        /// Defines a partition with the given rate limiter factory.
        /// </summary>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <remarks>
        /// The <paramref name="factory"/> should return a new instance of a rate limiter every time it is called.
        /// </remarks>
        /// <param name="partitionKey">The specific key for this partition. This will be used to check for an existing cached limiter before calling the <paramref name="factory"/>.</param>
        /// <param name="factory">The function called when a rate limiter for the given <paramref name="partitionKey"/> is needed. This should be a new instance of a rate limiter every time it is called.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> Get<TKey>(
            TKey partitionKey,
            Func<TKey, RateLimiter> factory)
        {
            return new RateLimitPartition<TKey>(partitionKey, factory);
        }
 
        /// <summary>
        /// Defines a partition with a <see cref="ConcurrencyLimiter"/> with the given <see cref="ConcurrencyLimiterOptions"/>.
        /// </summary>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <param name="partitionKey">The specific key for this partition. This will be used to check for an existing cached limiter before calling the <paramref name="factory"/>.</param>
        /// <param name="factory">The function called when a rate limiter for the given <paramref name="partitionKey"/> is needed. This can return the same instance of <see cref="ConcurrencyLimiterOptions"/> across different calls.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> GetConcurrencyLimiter<TKey>(
            TKey partitionKey,
            Func<TKey, ConcurrencyLimiterOptions> factory)
        {
            return Get(partitionKey, key => new ConcurrencyLimiter(factory(key)));
        }
 
        /// <summary>
        /// Defines a partition that will not have a rate limiter.
        /// This means any calls to <see cref="PartitionedRateLimiter{TResource}.AttemptAcquire(TResource, int)"/> or <see cref="PartitionedRateLimiter{TResource}.AcquireAsync(TResource, int, CancellationToken)"/> will always succeed for the given <paramref name="partitionKey"/>.
        /// </summary>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <param name="partitionKey">The specific key for this partition.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> GetNoLimiter<TKey>(TKey partitionKey)
        {
            return Get(partitionKey, _ => new NoopLimiter());
        }
 
        /// <summary>
        /// Defines a partition with a <see cref="TokenBucketRateLimiter"/> with the given <see cref="TokenBucketRateLimiterOptions"/>.
        /// </summary>
        /// <remarks>
        /// Set <see cref="TokenBucketRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> to save an allocation. This method will create a new options type and set <see cref="TokenBucketRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> otherwise.
        /// </remarks>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <param name="partitionKey">The specific key for this partition.</param>
        /// <param name="factory">The function called when a rate limiter for the given <paramref name="partitionKey"/> is needed. This can return the same instance of <see cref="TokenBucketRateLimiterOptions"/> across different calls.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> GetTokenBucketLimiter<TKey>(
            TKey partitionKey,
            Func<TKey, TokenBucketRateLimiterOptions> factory)
        {
            return Get(partitionKey, key =>
            {
                TokenBucketRateLimiterOptions options = factory(key);
                // We don't want individual TokenBucketRateLimiters to have timers. We will instead have our own internal Timer handling all of them
                if (options.AutoReplenishment is true)
                {
                    options = new TokenBucketRateLimiterOptions
                    {
                        TokenLimit = options.TokenLimit,
                        QueueProcessingOrder = options.QueueProcessingOrder,
                        QueueLimit = options.QueueLimit,
                        ReplenishmentPeriod = options.ReplenishmentPeriod,
                        TokensPerPeriod = options.TokensPerPeriod,
                        AutoReplenishment = false
                    };
                }
                return new TokenBucketRateLimiter(options);
            });
        }
 
        /// <summary>
        /// Defines a partition with a <see cref="SlidingWindowRateLimiter"/> with the given <see cref="SlidingWindowRateLimiterOptions"/>.
        /// </summary>
        /// <remarks>
        /// Set <see cref="SlidingWindowRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> to save an allocation. This method will create a new options type and set <see cref="SlidingWindowRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> otherwise.
        /// </remarks>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <param name="partitionKey">The specific key for this partition.</param>
        /// <param name="factory">The function called when a rate limiter for the given <paramref name="partitionKey"/> is needed. This can return the same instance of <see cref="SlidingWindowRateLimiterOptions"/> across different calls.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> GetSlidingWindowLimiter<TKey>(
            TKey partitionKey,
            Func<TKey, SlidingWindowRateLimiterOptions> factory)
        {
            return Get(partitionKey, key =>
            {
                SlidingWindowRateLimiterOptions options = factory(key);
                // We don't want individual SlidingWindowRateLimiters to have timers. We will instead have our own internal Timer handling all of them
                if (options.AutoReplenishment is true)
                {
                    options = new SlidingWindowRateLimiterOptions
                    {
                        PermitLimit = options.PermitLimit,
                        QueueProcessingOrder = options.QueueProcessingOrder,
                        QueueLimit = options.QueueLimit,
                        Window = options.Window,
                        SegmentsPerWindow = options.SegmentsPerWindow,
                        AutoReplenishment = false
                    };
                }
                return new SlidingWindowRateLimiter(options);
            });
        }
 
        /// <summary>
        /// Defines a partition with a <see cref="FixedWindowRateLimiter"/> with the given <see cref="FixedWindowRateLimiterOptions"/>.
        /// </summary>
        /// <remarks>
        /// Set <see cref="FixedWindowRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> to save an allocation. This method will create a new options type and set <see cref="FixedWindowRateLimiterOptions.AutoReplenishment"/> to <see langword="false"/> otherwise.
        /// </remarks>
        /// <typeparam name="TKey">The type to distinguish partitions with.</typeparam>
        /// <param name="partitionKey">The specific key for this partition.</param>
        /// <param name="factory">The function called when a rate limiter for the given <paramref name="partitionKey"/> is needed. This can return the same instance of <see cref="FixedWindowRateLimiterOptions"/> across different calls.</param>
        /// <returns></returns>
        public static RateLimitPartition<TKey> GetFixedWindowLimiter<TKey>(
            TKey partitionKey,
            Func<TKey, FixedWindowRateLimiterOptions> factory)
        {
            return Get(partitionKey, key =>
            {
                FixedWindowRateLimiterOptions options = factory(key);
                // We don't want individual FixedWindowRateLimiters to have timers. We will instead have our own internal Timer handling all of them
                if (options.AutoReplenishment is true)
                {
                    options = new FixedWindowRateLimiterOptions
                    {
                        PermitLimit = options.PermitLimit,
                        QueueProcessingOrder = options.QueueProcessingOrder,
                        QueueLimit = options.QueueLimit,
                        Window = options.Window,
                        AutoReplenishment = false
                    };
                }
                return new FixedWindowRateLimiter(options);
            });
        }
    }
}