Example #1
0
        public async void CanUseRateLimit()
        {
            Assert.True(LimitRequestZone.TryParse("zone=mylimit rate=10r/s", out var limitRequestZone));
            var delay = new MockDelay();
            var queue = new LeakyBucket(limitRequestZone, delay);

            Assert.Equal(1, queue.RemainingSlots);
            Assert.Equal(0, queue.UsedSlots);

            // 1st request should be processed immediately
            var wait       = queue.Throttle();
            var processing = queue.DrainNext();

            Assert.True(wait.Wait(10));
            Assert.Equal(0, queue.RemainingSlots);
            Assert.Equal(1, queue.UsedSlots);

            // 2nd request should be rejected
            Assert.False(await queue.Throttle());

            // Can't process, as we need to throttle
            Assert.False(processing.Wait(10));
            delay.AdvanceMilliseconds(99);
            Assert.False(processing.Wait(10));

            // Though after 100ms, it should works
            delay.AdvanceMilliseconds(1);
            Assert.True(processing.Wait(10));
            Assert.Equal(1, queue.RemainingSlots);
            Assert.Equal(0, queue.UsedSlots);
            processing = queue.DrainNext();
            await queue.Throttle();
        }
Example #2
0
        public void CanUseRateLimitWithBurstNoDelay()
        {
            Assert.True(LimitRequestZone.TryParse("zone=mylimit rate=10r/s burst=20 nodelay", out var limitRequestZone));
            var delay = new MockDelay();
            var queue = new LeakyBucket(limitRequestZone, delay);

            Assert.Equal(20, queue.RemainingSlots);
            Assert.Equal(0, queue.UsedSlots);
            // 1st request should be processed immediately
            var wait       = queue.Throttle();
            var processing = queue.DrainNext();

            Assert.True(wait.Wait(10));
            Assert.Equal(19, queue.RemainingSlots);
            Assert.Equal(1, queue.UsedSlots);
            Assert.True(processing.Wait(10)); // Thanks to nodelay processing do not have to wait

            // 2nd request should be processed immediately, but the slot kept
            wait       = queue.Throttle();
            processing = queue.DrainNext();
            Assert.True(wait.Wait(10));
            Assert.True(processing.Wait(10));       // Thanks to nodelay processing do not have to wait
            Assert.Equal(18, queue.RemainingSlots); // But the slots should not be free
            Assert.Equal(2, queue.UsedSlots);

            // Can process, thanks to nodelay
            delay.AdvanceMilliseconds(99);
            Assert.Equal(18, queue.RemainingSlots);
            Assert.Equal(2, queue.UsedSlots);

            // Though after 100ms, one slot should be freed, and the queued task executed
            delay.AdvanceMilliseconds(1);
            Thread.Sleep(1); // Sleep necessary as the WaitAfter is running concurrently
            Assert.Equal(19, queue.RemainingSlots);
            Assert.Equal(1, queue.UsedSlots);
            Thread.Sleep(1); // Sleep necessary as the WaitAfter is running concurrently

            // +100 ms passed, second slot if released
            delay.AdvanceMilliseconds(99);
            Assert.Equal(19, queue.RemainingSlots);
            delay.AdvanceMilliseconds(1);

            Thread.Sleep(1); // Sleep necessary as the WaitAfter is running concurrently
            Assert.Equal(20, queue.RemainingSlots);
        }
Example #3
0
        public void CanUseRateLimitWithBurst()
        {
            Assert.True(LimitRequestZone.TryParse("zone=mylimit rate=10r/s burst=20", out var limitRequestZone));
            var delay = new MockDelay();
            var queue = new LeakyBucket(limitRequestZone, delay);

            Assert.Equal(20, queue.RemainingSlots);
            Assert.Equal(0, queue.UsedSlots);

            // 1st request should be processed immediately
            var wait       = queue.Throttle();
            var processing = queue.DrainNext();

            Assert.True(wait.Wait(10));
            Assert.Equal(19, queue.RemainingSlots);
            Assert.Equal(1, queue.UsedSlots);

            // 2nd request should be queued
            wait = queue.Throttle();
            Assert.False(wait.Wait(10));
            Assert.Equal(18, queue.RemainingSlots);
            Assert.Equal(2, queue.UsedSlots);

            // Can't process, as we need to throttle
            Assert.False(processing.Wait(10));
            delay.AdvanceMilliseconds(99);
            Assert.False(processing.Wait(10));
            Assert.False(wait.Wait(10));

            // Though after 100ms, one slot should be freed, and the queued task executed
            delay.AdvanceMilliseconds(1);
            Assert.True(processing.Wait(10));
            processing = queue.DrainNext();
            Assert.True(wait.Wait(10));
            Assert.Equal(19, queue.RemainingSlots);
            Assert.Equal(1, queue.UsedSlots);

            // But still processing blocked...
            Assert.False(processing.Wait(10));
            // Until 100 ms passed
            delay.AdvanceMilliseconds(100);
            Assert.True(processing.Wait(10));
            Assert.Equal(20, queue.RemainingSlots);
        }
Example #4
0
        public async void CanUseRateLimitWithBurstNoDelay2()
        {
            Assert.True(LimitRequestZone.TryParse("zone=mylimit rate=10r/s burst=20 nodelay", out var limitRequestZone));
            var delay = new MockDelay();
            var queue = new LeakyBucket(limitRequestZone, delay);

            List <Task> waits = new List <Task>();

            for (int i = 0; i < 20; i++)
            {
                waits.Add(queue.Throttle());
            }
            Assert.False(await queue.Throttle());
            for (int i = 0; i < 20; i++)
            {
                delay.AdvanceMilliseconds(100);
                var processing = queue.DrainNext();
                Task.WaitAny(waits.ToArray());
                waits.RemoveAll(t => t.IsCompletedSuccessfully);
                Assert.Equal(20 - i - 1, waits.Count);
                Assert.True(processing.IsCompletedSuccessfully);
            }
        }