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(); }
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); }
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); }
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); } }