Esempio n. 1
0
        public async Task RetryMetadataOnFailedWaitAsync()
        {
            var options = new FixedWindowRateLimiterOptions
            {
                PermitLimit          = 2,
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                QueueLimit           = 1,
                Window            = TimeSpan.FromSeconds(20),
                AutoReplenishment = false
            };
            var limiter = new FixedWindowRateLimiter(options);

            using var lease = limiter.AttemptAcquire(2);

            var failedLease = await limiter.AcquireAsync(2);

            Assert.False(failedLease.IsAcquired);
            Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter.Name, out var metadata));
            var metaDataTime = Assert.IsType <TimeSpan>(metadata);

            Assert.Equal(options.Window.Ticks, metaDataTime.Ticks);

            Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata));
            Assert.Equal(options.Window.Ticks, typedMetadata.Ticks);
            Assert.Collection(failedLease.MetadataNames, item => item.Equals(MetadataName.RetryAfter.Name));
        }
        public void Create_FixedWindow()
        {
            var options   = new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromMinutes(1), true);
            var partition = RateLimitPartition.GetFixedWindowLimiter(1, key => options);

            var limiter            = partition.Factory(1);
            var fixedWindowLimiter = Assert.IsType <FixedWindowRateLimiter>(limiter);

            Assert.Equal(options.PermitLimit, fixedWindowLimiter.GetAvailablePermits());
            Assert.Equal(options.Window, fixedWindowLimiter.ReplenishmentPeriod);
            Assert.False(fixedWindowLimiter.IsAutoReplenishing);
        }
        public async Task CorrectRetryMetadataWithNonZeroAvailableItems()
        {
            var options = new FixedWindowRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 1,
                                                            TimeSpan.FromSeconds(20), autoReplenishment: false);
            var limiter = new FixedWindowRateLimiter(options);

            using var lease = limiter.Acquire(2);

            var failedLease = await limiter.WaitAsync(3);

            Assert.False(failedLease.IsAcquired);
            Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata));
            Assert.Equal(options.Window.Ticks, typedMetadata.Ticks);
        }
Esempio n. 4
0
 /// <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(options.PermitLimit, options.QueueProcessingOrder, options.QueueLimit,
                                                         options.Window, autoReplenishment: false);
         }
         return new FixedWindowRateLimiter(options);
     }));
 }
        public async Task CorrectRetryMetadataWithQueuedItem()
        {
            var options = new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1,
                                                            TimeSpan.FromSeconds(20), autoReplenishment: false);
            var limiter = new FixedWindowRateLimiter(options);

            using var lease = limiter.Acquire(2);
            // Queue item which changes the retry after time for failed items
            var wait = limiter.WaitAsync(1);

            Assert.False(wait.IsCompleted);

            var failedLease = await limiter.WaitAsync(2);

            Assert.False(failedLease.IsAcquired);
            Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata));
            Assert.Equal(options.Window.Ticks, typedMetadata.Ticks);
        }
    /// <summary>
    /// Adds a new <see cref="FixedWindowRateLimiter"/> with the given <see cref="FixedWindowRateLimiterOptions"/> to the <see cref="RateLimiterOptions"/>.
    /// </summary>
    /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param>
    /// <param name="policyName">The name that will be associated with the limiter.</param>
    /// <param name="configureOptions">A callback to configure the <see cref="FixedWindowRateLimiterOptions"/> to be used for the limiter.</param>
    /// <returns>This <see cref="RateLimiterOptions"/>.</returns>
    public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, Action <FixedWindowRateLimiterOptions> configureOptions)
    {
        ArgumentNullException.ThrowIfNull(configureOptions);

        var key = new PolicyNameKey()
        {
            PolicyName = policyName
        };
        var fixedWindowRateLimiterOptions = new FixedWindowRateLimiterOptions();

        configureOptions.Invoke(fixedWindowRateLimiterOptions);
        // Saves an allocation in GetFixedWindowLimiter, which would have created a new set of options if this was true.
        fixedWindowRateLimiterOptions.AutoReplenishment = false;
        return(options.AddPolicy(policyName, context =>
        {
            return RateLimitPartition.GetFixedWindowLimiter(key,
                                                            _ => fixedWindowRateLimiterOptions);
        }));
    }