public async Task Create_WithReplenishingLimiterReplenishesAutomatically()
        {
            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                // Use the non-specific Create method to make sure ReplenishingRateLimiters are still handled properly
                return(RateLimitPartition.Get(1,
                                              _ => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
                {
                    TokenLimit = 1,
                    QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
                    QueueLimit = 1,
                    ReplenishmentPeriod = TimeSpan.FromMilliseconds(100),
                    TokensPerPeriod = 1,
                    AutoReplenishment = false
                })));
            });

            var lease = limiter.AttemptAcquire("");

            Assert.True(lease.IsAcquired);

            lease = await limiter.AcquireAsync("");

            Assert.True(lease.IsAcquired);
        }
Ejemplo n.º 2
0
        public void Create_PassedInEqualityComparerIsUsed()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();
            var equality       = new TestEquality();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
                }
                return(RateLimitPartition.Get(2, key => limiterFactory.GetLimiter(key)));
            }, equality);

            limiter.Acquire("1");
            // GetHashCode to add item to dictionary (skips TryGet for empty dictionary)
            Assert.Equal(0, equality.EqualsCallCount);
            Assert.Equal(1, equality.GetHashCodeCallCount);
            limiter.Acquire("1");
            // GetHashCode and Equal from TryGet to see if item is in dictionary
            Assert.Equal(1, equality.EqualsCallCount);
            Assert.Equal(2, equality.GetHashCodeCallCount);
            limiter.Acquire("2");
            // GetHashCode from TryGet (fails check) and second GetHashCode to add item to dictionary
            Assert.Equal(1, equality.EqualsCallCount);
            Assert.Equal(4, equality.GetHashCodeCallCount);

            Assert.Equal(2, limiterFactory.Limiters.Count);
            Assert.Equal(2, limiterFactory.Limiters[0].Limiter.AcquireCallCount);
            Assert.Equal(1, limiterFactory.Limiters[1].Limiter.AcquireCallCount);
        }
Ejemplo n.º 3
0
        public async Task Create_MultipleReplenishingLimitersReplenishAutomatically()
        {
            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.GetTokenBucketLimiter(1,
                                                                    _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)));
                }
                return(RateLimitPartition.GetTokenBucketLimiter(2,
                                                                _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)));
            });

            var lease = limiter.Acquire("1");

            Assert.True(lease.IsAcquired);

            lease = await limiter.WaitAndAcquireAsync("1");

            Assert.True(lease.IsAcquired);

            // Creates the second Replenishing limiter
            // Indirectly tests that the cached list of limiters used by the timer is probably updated by making sure a limiter already made use of it before we create a second replenishing one
            lease = limiter.Acquire("2");
            Assert.True(lease.IsAcquired);

            lease = await limiter.WaitAndAcquireAsync("1");

            Assert.True(lease.IsAcquired);
            lease = await limiter.WaitAndAcquireAsync("2");

            Assert.True(lease.IsAcquired);
        }
Ejemplo n.º 4
0
        public async Task Create_BlockingWaitDoesNotBlockOtherPartitions()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
                }
                return(RateLimitPartition.GetConcurrencyLimiter(2,
                                                                _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2)));
            });

            var lease = await limiter.WaitAndAcquireAsync("2");

            var wait = limiter.WaitAndAcquireAsync("2");

            Assert.False(wait.IsCompleted);

            // Different partition, should not be blocked by the wait in the other partition
            await limiter.WaitAndAcquireAsync("1");

            lease.Dispose();
            await wait;

            Assert.Equal(1, limiterFactory.Limiters.Count);
            Assert.Equal(0, limiterFactory.Limiters[0].Limiter.AcquireCallCount);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.WaitAndAcquireAsyncCallCount);
        }
Ejemplo n.º 5
0
        public async Task IdleLimiterIsCleanedUp()
        {
            CustomizableLimiter innerLimiter = null;
            var factoryCallCount             = 0;

            using var limiter = Utils.CreatePartitionedLimiterWithoutTimer <string, int>(resource =>
            {
                return(RateLimitPartition.Get(1, _ =>
                {
                    factoryCallCount++;
                    innerLimiter = new CustomizableLimiter();
                    return innerLimiter;
                }));
            });

            var lease = limiter.Acquire("");

            Assert.True(lease.IsAcquired);

            Assert.Equal(1, factoryCallCount);

            var tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);

            innerLimiter.DisposeAsyncCoreImpl = () =>
            {
                tcs.SetResult(null);
                return(default);
Ejemplo n.º 6
0
        public void Create_AnyLimiter()
        {
            var partition = RateLimitPartition.Get(1, key => new ConcurrencyLimiter(new ConcurrencyLimiterOptions
            {
                PermitLimit          = 1,
                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
                QueueLimit           = 10
            }));

            var limiter            = partition.Factory(1);
            var concurrencyLimiter = Assert.IsType <ConcurrencyLimiter>(limiter);

            Assert.Equal(1, concurrencyLimiter.GetStatistics().CurrentAvailablePermits);

            var partition2 = RateLimitPartition.Get(1, key => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
            {
                TokenLimit           = 1,
                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
                QueueLimit           = 10,
                ReplenishmentPeriod  = TimeSpan.FromMilliseconds(100),
                TokensPerPeriod      = 1,
                AutoReplenishment    = false
            }));

            limiter = partition2.Factory(1);
            var tokenBucketLimiter = Assert.IsType <TokenBucketRateLimiter>(limiter);

            Assert.Equal(1, tokenBucketLimiter.GetStatistics().CurrentAvailablePermits);
        }
Ejemplo n.º 7
0
        public void Create_MultiplePartitionsWork()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
                }
                else
                {
                    return(RateLimitPartition.Get(2, key => limiterFactory.GetLimiter(key)));
                }
            });

            limiter.Acquire("1");
            limiter.Acquire("2");
            limiter.Acquire("1");
            limiter.Acquire("2");

            Assert.Equal(2, limiterFactory.Limiters.Count);

            Assert.Equal(2, limiterFactory.Limiters[0].Limiter.AcquireCallCount);
            Assert.Equal(1, limiterFactory.Limiters[0].Key);

            Assert.Equal(2, limiterFactory.Limiters[1].Limiter.AcquireCallCount);
            Assert.Equal(2, limiterFactory.Limiters[1].Key);
        }
Ejemplo n.º 8
0
 // Create the endpoint-specific PartitionedRateLimiter
 private PartitionedRateLimiter <HttpContext> CreateEndpointLimiter()
 {
     // If we have a policy for this endpoint, use its partitioner. Else use a NoLimiter.
     return(PartitionedRateLimiter.Create <HttpContext, DefaultKeyType>(context =>
     {
         DefaultRateLimiterPolicy?policy;
         var enableRateLimitingAttribute = context.GetEndpoint()?.Metadata.GetMetadata <EnableRateLimitingAttribute>();
         if (enableRateLimitingAttribute is null)
         {
             return RateLimitPartition.GetNoLimiter <DefaultKeyType>(_defaultPolicyKey);
         }
         policy = enableRateLimitingAttribute.Policy;
         if (policy is not null)
         {
             return policy.GetPartition(context);
         }
         var name = enableRateLimitingAttribute.PolicyName;
         if (name is not null)
         {
             if (_policyMap.TryGetValue(name, out policy))
             {
                 return policy.GetPartition(context);
             }
             else
             {
                 throw new InvalidOperationException($"This endpoint requires a rate limiting policy with name {name}, but no such policy exists.");
             }
         }
         // Should be impossible for both name & policy to be null, but throw in that scenario just in case.
         else
         {
             throw new InvalidOperationException("This endpoint requested a rate limiting policy with a null name.");
         }
     }, new DefaultKeyTypeEqualityComparer()));
 }
Ejemplo n.º 9
0
        public async Task Create_NoLimiter()
        {
            var partition = RateLimitPartition.CreateNoLimiter(1);

            var factoryProperty = typeof(RateLimitPartition <int>).GetField("Factory", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance) !;
            var factory         = (Func <int, RateLimiter>)factoryProperty.GetValue(partition);
            var limiter         = factory(1);

            // How do we test an internal implementation of a limiter that doesn't limit? Just try some stuff that normal limiters would probably block on and see if it works.
            var available = limiter.GetAvailablePermits();
            var lease     = limiter.Acquire(int.MaxValue);

            Assert.True(lease.IsAcquired);
            Assert.Equal(available, limiter.GetAvailablePermits());

            lease = limiter.Acquire(int.MaxValue);
            Assert.True(lease.IsAcquired);

            var wait = limiter.WaitAsync(int.MaxValue);

            Assert.True(wait.IsCompletedSuccessfully);
            lease = await wait;
            Assert.True(lease.IsAcquired);

            lease.Dispose();
        }
Ejemplo n.º 10
0
        public async Task Create_DisposeAsyncDisposesAllLimiters()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
                }
                return(RateLimitPartition.Get(2, key => limiterFactory.GetLimiter(key)));
            });

            limiter.Acquire("1");
            limiter.Acquire("2");

            await limiter.DisposeAsync();

            Assert.Equal(2, limiterFactory.Limiters.Count);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.AcquireCallCount);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.DisposeCallCount);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.DisposeAsyncCallCount);

            Assert.Equal(1, limiterFactory.Limiters[1].Limiter.AcquireCallCount);
            Assert.Equal(1, limiterFactory.Limiters[1].Limiter.DisposeCallCount);
            Assert.Equal(1, limiterFactory.Limiters[1].Limiter.DisposeAsyncCallCount);
        }
Ejemplo n.º 11
0
    public void AddPolicy_Generic_ThrowsOnDuplicateName()
    {
        var options = new RateLimiterOptions();

        options.AddPolicy <string>("myKey", context => RateLimitPartition.GetNoLimiter <string>("myKey"));
        Assert.Throws <ArgumentException>(() => options.AddPolicy <string, TestRateLimiterPolicy>("myKey"));
    }
Ejemplo n.º 12
0
 // Converts a Partition<TKey> to a Partition<DefaultKeyType<TKey>> to prevent accidental collisions with the keys we create in the the RateLimiterOptionsExtensions.
 internal static Func <HttpContext, RateLimitPartition <DefaultKeyType> > ConvertPartitioner <TPartitionKey>(string?policyName, Func <HttpContext, RateLimitPartition <TPartitionKey> > partitioner)
 {
     return(context =>
     {
         RateLimitPartition <TPartitionKey> partition = partitioner(context);
         var partitionKey = new DefaultKeyType(policyName, partition.PartitionKey, partition.Factory);
         return new RateLimitPartition <DefaultKeyType>(partitionKey, static key => ((Func <TPartitionKey, RateLimiter>)key.Factory !)((TPartitionKey)key.Key !));
     });
 }
Ejemplo n.º 13
0
        public void Create_Concurrency()
        {
            var options   = new ConcurrencyLimiterOptions(10, QueueProcessingOrder.OldestFirst, 10);
            var partition = RateLimitPartition.GetConcurrencyLimiter(1, key => options);

            var limiter            = partition.Factory(1);
            var concurrencyLimiter = Assert.IsType <ConcurrencyLimiter>(limiter);

            Assert.Equal(options.PermitLimit, concurrencyLimiter.GetAvailablePermits());
        }
Ejemplo n.º 14
0
        public void Create_Concurrency()
        {
            var options   = new ConcurrencyLimiterOptions(10, QueueProcessingOrder.OldestFirst, 10);
            var partition = RateLimitPartition.CreateConcurrencyLimiter(1, key => options);

            var factoryProperty    = typeof(RateLimitPartition <int>).GetField("Factory", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance) !;
            var factory            = (Func <int, RateLimiter>)factoryProperty.GetValue(partition);
            var limiter            = factory(1);
            var concurrencyLimiter = Assert.IsType <ConcurrencyLimiter>(limiter);

            Assert.Equal(options.PermitLimit, concurrencyLimiter.GetAvailablePermits());
        }
Ejemplo n.º 15
0
        public void Create_SlidingWindow()
        {
            var options   = new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromSeconds(33), 3, true);
            var partition = RateLimitPartition.GetSlidingWindowLimiter(1, key => options);

            var limiter = partition.Factory(1);
            var slidingWindowLimiter = Assert.IsType <SlidingWindowRateLimiter>(limiter);

            Assert.Equal(options.PermitLimit, slidingWindowLimiter.GetAvailablePermits());
            Assert.Equal(TimeSpan.FromSeconds(11), slidingWindowLimiter.ReplenishmentPeriod);
            Assert.False(slidingWindowLimiter.IsAutoReplenishing);
        }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 17
0
        public void Create_TokenBucket()
        {
            var options   = new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromMinutes(1), 1, true);
            var partition = RateLimitPartition.GetTokenBucketLimiter(1, key => options);

            var limiter            = partition.Factory(1);
            var tokenBucketLimiter = Assert.IsType <TokenBucketRateLimiter>(limiter);

            Assert.Equal(options.TokenLimit, tokenBucketLimiter.GetAvailablePermits());
            Assert.Equal(options.ReplenishmentPeriod, tokenBucketLimiter.ReplenishmentPeriod);
            Assert.False(tokenBucketLimiter.IsAutoReplenishing);
        }
Ejemplo n.º 18
0
        public void Create_GetAvailablePermitsCallsUnderlyingPartitionsLimiter()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
            });

            limiter.GetAvailablePermits("");
            Assert.Equal(1, limiterFactory.Limiters.Count);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.GetAvailablePermitsCallCount);
        }
Ejemplo n.º 19
0
        public void Create_DisposeWithoutLimitersNoops()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
            });

            limiter.Dispose();

            Assert.Equal(0, limiterFactory.Limiters.Count);
        }
Ejemplo n.º 20
0
        public void Create_TokenBucket()
        {
            var options   = new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromMinutes(1), 1, true);
            var partition = RateLimitPartition.CreateTokenBucketLimiter(1, key => options);

            var factoryProperty    = typeof(RateLimitPartition <int>).GetField("Factory", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance) !;
            var factory            = (Func <int, RateLimiter>)factoryProperty.GetValue(partition);
            var limiter            = factory(1);
            var tokenBucketLimiter = Assert.IsType <TokenBucketRateLimiter>(limiter);

            Assert.Equal(options.TokenLimit, tokenBucketLimiter.GetAvailablePermits());
            // TODO: Check other properties when ReplenshingRateLimiter is merged
            // TODO: Check that autoReplenishment: true got changed to false
        }
Ejemplo n.º 21
0
        public async Task Create_WaitAsyncCallsUnderlyingPartitionsLimiter()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
            });

            await limiter.WaitAndAcquireAsync("");

            Assert.Equal(1, limiterFactory.Limiters.Count);
            Assert.Equal(1, limiterFactory.Limiters[0].Limiter.WaitAndAcquireAsyncCallCount);
        }
Ejemplo n.º 22
0
        public async Task Create_BlockingFactoryDoesNotBlockOtherPartitions()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();
            var tcs            = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);
            var startedTcs     = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                if (resource == "1")
                {
                    return(RateLimitPartition.Get(1, key =>
                    {
                        startedTcs.SetResult(null);
                        // block the factory method
                        Assert.True(tcs.Task.Wait(TimeSpan.FromSeconds(10)));
                        return limiterFactory.GetLimiter(key);
                    }));
                }
                return(RateLimitPartition.Get(2,
                                              key => limiterFactory.GetLimiter(key)));
            });

            var lease = await limiter.WaitAndAcquireAsync("2");

            var blockedTask = Task.Run(async() =>
            {
                await limiter.WaitAndAcquireAsync("1");
            });
            await startedTcs.Task;

            // Other partitions aren't blocked
            await limiter.WaitAndAcquireAsync("2");

            // Try to acquire from the blocking limiter, this should wait until the blocking limiter has been resolved and not create a new one
            var blockedTask2 = Task.Run(async() =>
            {
                await limiter.WaitAndAcquireAsync("1");
            });

            // unblock limiter factory
            tcs.SetResult(null);
            await blockedTask;
            await blockedTask2;

            // Only 2 limiters should have been created
            Assert.Equal(2, limiterFactory.Limiters.Count);
            Assert.Equal(2, limiterFactory.Limiters[0].Limiter.WaitAndAcquireAsyncCallCount);
            Assert.Equal(2, limiterFactory.Limiters[1].Limiter.WaitAndAcquireAsyncCallCount);
        }
Ejemplo n.º 23
0
        public void Create_DisposeThrowsForFutureMethodCalls()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)));
            });

            limiter.Dispose();

            Assert.Throws <ObjectDisposedException>(() => limiter.Acquire("1"));

            Assert.Equal(0, limiterFactory.Limiters.Count);
        }
Ejemplo n.º 24
0
        public async Task Create_WithTokenBucketReplenishesAutomatically()
        {
            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.GetTokenBucketLimiter(1,
                                                                _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)));
            });

            var lease = limiter.Acquire("");

            Assert.True(lease.IsAcquired);

            lease = await limiter.WaitAndAcquireAsync("");

            Assert.True(lease.IsAcquired);
        }
Ejemplo n.º 25
0
        public void Create_AnyLimiter()
        {
            var partition = RateLimitPartition.Get(1, key => new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10)));

            var limiter            = partition.Factory(1);
            var concurrencyLimiter = Assert.IsType <ConcurrencyLimiter>(limiter);

            Assert.Equal(1, concurrencyLimiter.GetAvailablePermits());

            var partition2 = RateLimitPartition.Get(1, key => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10, TimeSpan.FromMilliseconds(100), 1, autoReplenishment: false)));

            limiter = partition2.Factory(1);
            var tokenBucketLimiter = Assert.IsType <TokenBucketRateLimiter>(limiter);

            Assert.Equal(1, tokenBucketLimiter.GetAvailablePermits());
        }
    /// <summary>
    /// Adds a new <see cref="ConcurrencyLimiter"/> with the given <see cref="ConcurrencyLimiterOptions"/> 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="ConcurrencyLimiterOptions"/> to be used for the limiter.</param>
    /// <returns>This <see cref="RateLimiterOptions"/>.</returns>
    public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, Action <ConcurrencyLimiterOptions> configureOptions)
    {
        ArgumentNullException.ThrowIfNull(configureOptions);

        var key = new PolicyNameKey()
        {
            PolicyName = policyName
        };
        var concurrencyLimiterOptions = new ConcurrencyLimiterOptions();

        configureOptions.Invoke(concurrencyLimiterOptions);
        return(options.AddPolicy(policyName, context =>
        {
            return RateLimitPartition.GetConcurrencyLimiter(key,
                                                            _ => concurrencyLimiterOptions);
        }));
    }
Ejemplo n.º 27
0
        public async Task NoLimiter_GetStatistics()
        {
            var partition = RateLimitPartition.GetNoLimiter(1);

            var limiter = partition.Factory(1);

            var stats = limiter.GetStatistics();

            Assert.NotSame(stats, limiter.GetStatistics());
            Assert.Equal(long.MaxValue, stats.CurrentAvailablePermits);
            Assert.Equal(0, stats.CurrentQueuedCount);
            Assert.Equal(0, stats.TotalFailedLeases);
            Assert.Equal(0, stats.TotalSuccessfulLeases);

            var leaseCount = 0;

            for (var i = 0; i < 134; i++)
            {
                var lease = limiter.AttemptAcquire(i);
                Assert.True(lease.IsAcquired);
                ++leaseCount;
            }

            stats = limiter.GetStatistics();
            Assert.Equal(long.MaxValue, stats.CurrentAvailablePermits);
            Assert.Equal(0, stats.CurrentQueuedCount);
            Assert.Equal(0, stats.TotalFailedLeases);
            Assert.Equal(leaseCount, stats.TotalSuccessfulLeases);

            for (var i = 0; i < 165; i++)
            {
                var wait = limiter.AcquireAsync(int.MaxValue);
                Assert.True(wait.IsCompletedSuccessfully);
                var lease = await wait;
                Assert.True(lease.IsAcquired);
                ++leaseCount;
            }

            stats = limiter.GetStatistics();
            Assert.Equal(long.MaxValue, stats.CurrentAvailablePermits);
            Assert.Equal(0, stats.CurrentQueuedCount);
            Assert.Equal(0, stats.TotalFailedLeases);
            Assert.Equal(leaseCount, stats.TotalSuccessfulLeases);
        }
Ejemplo n.º 28
0
        public async Task Create_PartitionIsCached()
        {
            var limiterFactory = new TrackingRateLimiterFactory <int>();

            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.Create(1, key => limiterFactory.GetLimiter(key)));
            });

            limiter.Acquire("");
            await limiter.WaitAsync("");

            limiter.Acquire("");
            await limiter.WaitAsync("");

            Assert.Equal(1, limiterFactory.Limiters.Count);
            Assert.Equal(2, limiterFactory.Limiters[0].Limiter.AcquireCallCount);
            Assert.Equal(2, limiterFactory.Limiters[0].Limiter.WaitAsyncCallCount);
        }
Ejemplo n.º 29
0
        public void Create_AnyLimiter()
        {
            var partition = RateLimitPartition.Create(1, key => new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10)));

            var factoryProperty    = typeof(RateLimitPartition <int>).GetField("Factory", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance) !;
            var factory            = (Func <int, RateLimiter>)factoryProperty.GetValue(partition);
            var limiter            = factory(1);
            var concurrencyLimiter = Assert.IsType <ConcurrencyLimiter>(limiter);

            Assert.Equal(1, concurrencyLimiter.GetAvailablePermits());

            var partition2 = RateLimitPartition.Create(1, key => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10, TimeSpan.FromMilliseconds(100), 1, autoReplenishment: false)));

            factory = (Func <int, RateLimiter>)factoryProperty.GetValue(partition2);
            limiter = factory(1);
            var tokenBucketLimiter = Assert.IsType <TokenBucketRateLimiter>(limiter);

            Assert.Equal(1, tokenBucketLimiter.GetAvailablePermits());
        }
Ejemplo n.º 30
0
        public async Task Create_CancellationTokenPassedToUnderlyingLimiter()
        {
            using var limiter = PartitionedRateLimiter.Create <string, int>(resource =>
            {
                return(RateLimitPartition.GetConcurrencyLimiter(1,
                                                                _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)));
            });

            var lease = limiter.Acquire("");

            Assert.True(lease.IsAcquired);

            var cts      = new CancellationTokenSource();
            var waitTask = limiter.WaitAndAcquireAsync("", 1, cts.Token);

            Assert.False(waitTask.IsCompleted);
            cts.Cancel();
            await Assert.ThrowsAsync <TaskCanceledException>(async() => await waitTask);
        }