From 2e7c052da707042d78e0510abd0019d7a0d142bc Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:26:06 -0700 Subject: [PATCH 01/60] Update ConcurrencyLimiterOptions.cs --- .../RateLimiting/ConcurrencyLimiterOptions.cs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs index 104de7cd3f04ef..b0f1130406a7d1 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs @@ -8,32 +8,11 @@ namespace System.Threading.RateLimiting /// public sealed class ConcurrencyLimiterOptions { - /// - /// Initializes the . - /// - /// Maximum number of permits that can be leased concurrently. - /// Determines the behaviour of when not enough resources can be leased. - /// Maximum number of permits that can be queued concurrently. - /// When or are less than 0. - public ConcurrencyLimiterOptions(int permitLimit, QueueProcessingOrder queueProcessingOrder, int queueLimit) - { - if (permitLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(permitLimit)); - } - if (queueLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(queueLimit)); - } - PermitLimit = permitLimit; - QueueProcessingOrder = queueProcessingOrder; - QueueLimit = queueLimit; - } - /// /// Maximum number of permits that can be leased concurrently. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; } + public int PermitLimit { get; set; } = 0; /// /// Determines the behaviour of when not enough resources can be leased. @@ -41,11 +20,12 @@ public ConcurrencyLimiterOptions(int permitLimit, QueueProcessingOrder queueProc /// /// by default. /// - public QueueProcessingOrder QueueProcessingOrder { get; } = QueueProcessingOrder.OldestFirst; + public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst; /// /// Maximum number of permits that can be queued concurrently. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; } + public int QueueLimit { get; set; } = 0; } } From 986b892dfd5b79e77713f2daeb73cda88954dc7c Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:29:24 -0700 Subject: [PATCH 02/60] Update FixedWindowRateLimiterOptions.cs --- .../FixedWindowRateLimiterOptions.cs | 50 ++++--------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index a1a88deb7f04f7..9394887bfca475 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -8,57 +8,24 @@ namespace System.Threading.RateLimiting /// public sealed class FixedWindowRateLimiterOptions { - /// - /// Initializes the . - /// - /// Maximum number of requests that can be served in the window. - /// - /// Maximum number of unprocessed request counters waiting via . - /// - /// Specifies how often request counters can be replenished. Replenishing is triggered either by an internal timer if is true, or by calling . - /// - /// - /// Specifies whether request replenishment will be handled by the or by another party via . - /// - /// When or are less than 0. - public FixedWindowRateLimiterOptions( - int permitLimit, - QueueProcessingOrder queueProcessingOrder, - int queueLimit, - TimeSpan window, - bool autoReplenishment = true) - { - if (permitLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(permitLimit)); - } - if (queueLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(queueLimit)); - } - - PermitLimit = permitLimit; - QueueProcessingOrder = queueProcessingOrder; - QueueLimit = queueLimit; - Window = window; - AutoReplenishment = autoReplenishment; - } - /// /// Specifies the time window that takes in the requests. + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public TimeSpan Window { get; } + public TimeSpan Window { get; set; } = TimeSpan.Zero; /// /// Specified whether the is automatically refresh counters or if someone else /// will be calling to refresh counters. + // 'true' by default. /// - public bool AutoReplenishment { get; } + public bool AutoReplenishment { get; set; } = true; /// /// Maximum number of permit counters that can be allowed in a window. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; } + public int PermitLimit { get; set; } = 0; /// /// Determines the behaviour of when not enough resources can be leased. @@ -66,11 +33,12 @@ public FixedWindowRateLimiterOptions( /// /// by default. /// - public QueueProcessingOrder QueueProcessingOrder { get; } + public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst; /// /// Maximum cumulative permit count of queued acquisition requests. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; } + public int QueueLimit { get; set; } = 0; } } From e7f7dbb7dde81480297cb750a86b14a40a4b5ba6 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:31:00 -0700 Subject: [PATCH 03/60] Update FixedWindowRateLimiterOptions.cs --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index 9394887bfca475..e83b72d83a04f1 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class FixedWindowRateLimiterOptions { /// /// Specifies the time window that takes in the requests. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// public TimeSpan Window { get; set; } = TimeSpan.Zero; @@ -23,7 +23,7 @@ public sealed class FixedWindowRateLimiterOptions /// /// Maximum number of permit counters that can be allowed in a window. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// public int PermitLimit { get; set; } = 0; @@ -37,7 +37,7 @@ public sealed class FixedWindowRateLimiterOptions /// /// Maximum cumulative permit count of queued acquisition requests. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// public int QueueLimit { get; set; } = 0; } From 6d68534381acca8fcdb38a76c7935df6fd94d0ff Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:33:22 -0700 Subject: [PATCH 04/60] Update FixedWindowRateLimiterOptions.cs --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index e83b72d83a04f1..11bbdde0a9250d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -17,8 +17,10 @@ public sealed class FixedWindowRateLimiterOptions /// /// Specified whether the is automatically refresh counters or if someone else /// will be calling to refresh counters. - // 'true' by default. /// + /// + /// 'true' by default. + /// public bool AutoReplenishment { get; set; } = true; /// From 4b40874584fd2370f2e6301440399ceec51f1d57 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:35:16 -0700 Subject: [PATCH 05/60] Update SlidingWindowRateLimiterOptions.cs --- .../SlidingWindowRateLimiterOptions.cs | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index 075f247471b85a..3c61d884f2806b 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -8,69 +8,32 @@ namespace System.Threading.RateLimiting /// public sealed class SlidingWindowRateLimiterOptions { - /// - /// Initializes the . - /// - /// Maximum number of request counters that can be served in a window. - /// - /// Maximum number of unprocessed request counters waiting via . - /// - /// Specifies how often requests can be replenished. Replenishing is triggered either by an internal timer if is true, or by calling . - /// - /// Specified how many segments a window can be divided into. The total requests a segment can serve cannot exceed the max limit.. - /// - /// Specifies whether request replenishment will be handled by the or by another party via . - /// - /// When , , or are less than 0. - public SlidingWindowRateLimiterOptions( - int permitLimit, - QueueProcessingOrder queueProcessingOrder, - int queueLimit, - TimeSpan window, - int segmentsPerWindow, - bool autoReplenishment = true) - { - if (permitLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(permitLimit)); - } - if (queueLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(queueLimit)); - } - if (segmentsPerWindow <= 0) - { - throw new ArgumentOutOfRangeException(nameof(segmentsPerWindow)); - } - - PermitLimit = permitLimit; - QueueProcessingOrder = queueProcessingOrder; - QueueLimit = queueLimit; - Window = window; - SegmentsPerWindow = segmentsPerWindow; - AutoReplenishment = autoReplenishment; - } - /// /// Specifies the minimum period between replenishments. + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public TimeSpan Window { get; } + public TimeSpan Window { get; set; } = TimeSpan.Zero; /// /// Specifies the maximum number of segments a window is divided into. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int SegmentsPerWindow { get; } + public int SegmentsPerWindow { get; set; } = 0; /// /// Specified whether the is automatically replenishing request counters or if someone else /// will be calling to replenish tokens. /// - public bool AutoReplenishment { get; } + /// + /// 'true' by default. + /// + public bool AutoReplenishment { get; set; } = true; /// /// Maximum number of requests that can be served in a window. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; } + public int PermitLimit { get; set; } = 0; /// /// Determines the behaviour of when not enough resources can be leased. @@ -78,11 +41,12 @@ public SlidingWindowRateLimiterOptions( /// /// by default. /// - public QueueProcessingOrder QueueProcessingOrder { get; } + public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst; /// /// Maximum cumulative permit count of queued acquisition requests. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; } + public int QueueLimit { get; set; } = 0; } } From 4ae07318997a63cf41e553e7edcbdbb9a7576851 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:38:49 -0700 Subject: [PATCH 06/60] Update TokenBucketRateLimiterOptions.cs --- .../TokenBucketRateLimiterOptions.cs | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index 6c644ef85b077e..2e703792f99a5c 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -8,69 +8,32 @@ namespace System.Threading.RateLimiting /// public sealed class TokenBucketRateLimiterOptions { - /// - /// Initializes the . - /// - /// Maximum number of tokens that can be in the token bucket. - /// - /// Maximum number of unprocessed tokens waiting via . - /// - /// Specifies how often tokens can be replenished. Replenishing is triggered either by an internal timer if is true, or by calling . - /// - /// Specified how many tokens can be added to the token bucket on a successful replenish. Available token count will not exceed . - /// - /// Specifies whether token replenishment will be handled by the or by another party via . - /// - /// When , , or are less than 0. - public TokenBucketRateLimiterOptions( - int tokenLimit, - QueueProcessingOrder queueProcessingOrder, - int queueLimit, - TimeSpan replenishmentPeriod, - int tokensPerPeriod, - bool autoReplenishment = true) - { - if (tokenLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenLimit)); - } - if (queueLimit < 0) - { - throw new ArgumentOutOfRangeException(nameof(queueLimit)); - } - if (tokensPerPeriod <= 0) - { - throw new ArgumentOutOfRangeException(nameof(tokensPerPeriod)); - } - - TokenLimit = tokenLimit; - QueueProcessingOrder = queueProcessingOrder; - QueueLimit = queueLimit; - ReplenishmentPeriod = replenishmentPeriod; - TokensPerPeriod = tokensPerPeriod; - AutoReplenishment = autoReplenishment; - } - /// /// Specifies the minimum period between replenishments. + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public TimeSpan ReplenishmentPeriod { get; } + public TimeSpan ReplenishmentPeriod { get; set; } = TimeSpan.Zero; /// /// Specifies the maximum number of tokens to restore each replenishment. + /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int TokensPerPeriod { get; } + public int TokensPerPeriod { get; set; } = 0; /// /// Specified whether the is automatically replenishing tokens or if someone else /// will be calling to replenish tokens. /// - public bool AutoReplenishment { get; } + /// + /// 'true' by default. + /// + public bool AutoReplenishment { get; set; } = true; /// /// Maximum number of tokens that can be in the bucket at any time. + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public int TokenLimit { get; } + public int TokenLimit { get; set; } = 0; /// /// Determines the behaviour of when not enough resources can be leased. @@ -78,11 +41,12 @@ public TokenBucketRateLimiterOptions( /// /// by default. /// - public QueueProcessingOrder QueueProcessingOrder { get; } + public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst; /// /// Maximum cumulative token count of queued acquisition requests. + /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public int QueueLimit { get; } + public int QueueLimit { get; set; } = 0; } } From e8e3c311e0a11caf4d92802813cdf9d957a15b00 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:45:55 -0700 Subject: [PATCH 07/60] Update ConcurrencyLimiter.cs --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 2b38d6d0eed005..aef7c096448ba6 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -39,6 +39,10 @@ public sealed class ConcurrencyLimiter : RateLimiter public ConcurrencyLimiter(ConcurrencyLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + if (options.PermitLimit <= 0 || options.QueueLimit <= 0) + { + throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.QueueLimit)} must be set to values >= 0."); + } _permitCount = _options.PermitLimit; } From 72b56f9b97b3e373c957daa666b2119bdd9096cd Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:49:56 -0700 Subject: [PATCH 08/60] Update FixedWindowRateLimiter.cs --- .../System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index c6b1b67ada3109..48ba8c9cff630f 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -45,6 +45,10 @@ public sealed class FixedWindowRateLimiter : ReplenishingRateLimiter public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.Window.Equals(TimeSpan.Zero)) + { + throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, and {nameof(options.Window)} must all be set to values >= 0."); + } _requestCount = options.PermitLimit; _idleSince = _lastReplenishmentTick = Stopwatch.GetTimestamp(); From d4a7eac4b3d8851add0d9b816243e91ceae67c73 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:51:31 -0700 Subject: [PATCH 09/60] Update SlidingWindowRateLimiter.cs --- .../System/Threading/RateLimiting/SlidingWindowRateLimiter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 5911ef439afc24..3ef09cb7b99c6a 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -48,6 +48,10 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.SegmentsPerWindow <= 0 || options.Window.Equals(TimeSpan.Zero)) + { + throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values >= 0."); + } _requestCount = options.PermitLimit; // _requestsPerSegment holds the no. of acquired requests in each window segment From 1ed959ba3e79efe714b61b40383428b01b30d4ee Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:53:06 -0700 Subject: [PATCH 10/60] Update TokenBucketRateLimiter.cs --- .../System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index d971fc3a134663..28a5474af89a46 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -46,6 +46,10 @@ public sealed class TokenBucketRateLimiter : ReplenishingRateLimiter public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + if (options.TokenLimit <= 0 || options.QueueLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) + { + throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.QueueLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values >= 0."); + } _tokenCount = options.TokenLimit; _idleSince = _lastReplenishmentTick = Stopwatch.GetTimestamp(); From d40805d5679ef25a25cd34540dfdfd99d5afd349 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 08:59:14 -0700 Subject: [PATCH 11/60] Update ChainedLimiterTests.cs --- .../tests/ChainedLimiterTests.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs index c0fc937d554391..20930f9a09101e 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs @@ -44,13 +44,23 @@ public async Task DisposeMakesMethodsThrow() Assert.Throws(() => chainedLimiter.Acquire("")); await Assert.ThrowsAsync(async () => await chainedLimiter.WaitAndAcquireAsync("")); } - +new StudentName + { + FirstName = "Craig", + LastName = "Playstead" + }; [Fact] public async Task DisposeAsyncMakesMethodsThrow() { using var limiter1 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }) }); using var limiter2 = PartitionedRateLimiter.Create(resource => { From 9f27a6bb20bb19135381bb94612c5d625f6aa614 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 09:29:41 -0700 Subject: [PATCH 12/60] Update ConcurrencyLimiterOptions.cs --- .../Threading/RateLimiting/ConcurrencyLimiterOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs index b0f1130406a7d1..6dfb625e1dcc9c 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs @@ -12,7 +12,7 @@ public sealed class ConcurrencyLimiterOptions /// Maximum number of permits that can be leased concurrently. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; set; } = 0; + public int PermitLimit { get; set; } /// /// Determines the behaviour of when not enough resources can be leased. @@ -26,6 +26,6 @@ public sealed class ConcurrencyLimiterOptions /// Maximum number of permits that can be queued concurrently. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; set; } = 0; + public int QueueLimit { get; set; } } } From 71d005bfdeb6838adcf5dbb539c6f68687703528 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 09:30:24 -0700 Subject: [PATCH 13/60] Update FixedWindowRateLimiterOptions.cs --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index 11bbdde0a9250d..6f4dfa279d6dbc 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -27,7 +27,7 @@ public sealed class FixedWindowRateLimiterOptions /// Maximum number of permit counters that can be allowed in a window. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; set; } = 0; + public int PermitLimit { get; set; } /// /// Determines the behaviour of when not enough resources can be leased. @@ -41,6 +41,6 @@ public sealed class FixedWindowRateLimiterOptions /// Maximum cumulative permit count of queued acquisition requests. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; set; } = 0; + public int QueueLimit { get; set; } } } From 56335d412251fdd44b6dc3ab1b4e92b825feb1db Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 09:31:24 -0700 Subject: [PATCH 14/60] Update SlidingWindowRateLimiterOptions.cs --- .../RateLimiting/SlidingWindowRateLimiterOptions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index 3c61d884f2806b..bfb144017dc45d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -18,7 +18,7 @@ public sealed class SlidingWindowRateLimiterOptions /// Specifies the maximum number of segments a window is divided into. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int SegmentsPerWindow { get; set; } = 0; + public int SegmentsPerWindow { get; set; } /// /// Specified whether the is automatically replenishing request counters or if someone else @@ -33,7 +33,7 @@ public sealed class SlidingWindowRateLimiterOptions /// Maximum number of requests that can be served in a window. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int PermitLimit { get; set; } = 0; + public int PermitLimit { get; set; } /// /// Determines the behaviour of when not enough resources can be leased. @@ -47,6 +47,6 @@ public sealed class SlidingWindowRateLimiterOptions /// Maximum cumulative permit count of queued acquisition requests. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int QueueLimit { get; set; } = 0; + public int QueueLimit { get; set; } } } From 9453bf306b6c9bb15bb73275bdbe5c711aa760e8 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 09:32:11 -0700 Subject: [PATCH 15/60] Update TokenBucketRateLimiterOptions.cs --- .../Threading/RateLimiting/TokenBucketRateLimiterOptions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index 2e703792f99a5c..894f77c1b7676f 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -18,7 +18,7 @@ public sealed class TokenBucketRateLimiterOptions /// Specifies the maximum number of tokens to restore each replenishment. /// Must be set to a value >= 0 by the team these options are passed to the constructor of . /// - public int TokensPerPeriod { get; set; } = 0; + public int TokensPerPeriod { get; set; } /// /// Specified whether the is automatically replenishing tokens or if someone else @@ -33,7 +33,7 @@ public sealed class TokenBucketRateLimiterOptions /// Maximum number of tokens that can be in the bucket at any time. /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public int TokenLimit { get; set; } = 0; + public int TokenLimit { get; set; } /// /// Determines the behaviour of when not enough resources can be leased. @@ -47,6 +47,6 @@ public sealed class TokenBucketRateLimiterOptions /// Maximum cumulative token count of queued acquisition requests. /// Must be set to a nonzero value by the team these options are passed to the constructor of . /// - public int QueueLimit { get; set; } = 0; + public int QueueLimit { get; set; } } } From 5ebd688ea53c9f3aa502ce6e6cf2d9c79bc97a27 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 09:39:12 -0700 Subject: [PATCH 16/60] Update RateLimitPartition.cs --- .../RateLimiting/RateLimitPartition.cs | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitPartition.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitPartition.cs index 4042cce53141b1..f6b3e1a2ad0e93 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitPartition.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitPartition.cs @@ -71,8 +71,15 @@ public static RateLimitPartition GetTokenBucketLimiter( // 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(options.TokenLimit, options.QueueProcessingOrder, options.QueueLimit, - options.ReplenishmentPeriod, options.TokensPerPeriod, autoReplenishment: false); + options = new TokenBucketRateLimiterOptions + { + TokenLimit = options.TokenLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + ReplenishmentPeriod = options.ReplenishmentPeriod, + TokensPerPeriod = options.TokensPerPeriod, + AutoReplenishment = false + }; } return new TokenBucketRateLimiter(options); }); @@ -98,8 +105,15 @@ public static RateLimitPartition GetSlidingWindowLimiter( // 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(options.PermitLimit, options.QueueProcessingOrder, options.QueueLimit, - options.Window, options.SegmentsPerWindow, autoReplenishment: false); + options = new SlidingWindowRateLimiterOptions + { + PermitLimit = options.PermitLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + Window = options.Window, + SegmentsPerWindow = options.SegmentsPerWindow, + AutoReplenishment = false + }; } return new SlidingWindowRateLimiter(options); }); @@ -125,8 +139,14 @@ public static RateLimitPartition GetFixedWindowLimiter( // 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); + options = new FixedWindowRateLimiterOptions + { + PermitLimit = options.PermitLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + Window = options.Window, + AutoReplenishment = false + }; } return new FixedWindowRateLimiter(options); }); From d5f10c0632628faf5e47941982342664bdaf8854 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 10:11:21 -0700 Subject: [PATCH 17/60] Update System.Threading.RateLimiting.cs --- .../ref/System.Threading.RateLimiting.cs | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs b/src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs index 6a3a710ff8a069..f6191054f5ee69 100644 --- a/src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs +++ b/src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs @@ -18,10 +18,10 @@ protected override void Dispose(bool disposing) { } } public sealed partial class ConcurrencyLimiterOptions { - public ConcurrencyLimiterOptions(int permitLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit) { } - public int PermitLimit { get { throw null; } } - public int QueueLimit { get { throw null; } } - public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } } + public ConcurrencyLimiterOptions() { } + public int PermitLimit { get { throw null; } set { throw null; } } + public int QueueLimit { get { throw null; } set { throw null; } } + public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } set { throw null; } } } public sealed partial class FixedWindowRateLimiter : System.Threading.RateLimiting.ReplenishingRateLimiter { @@ -38,12 +38,12 @@ protected override void Dispose(bool disposing) { } } public sealed partial class FixedWindowRateLimiterOptions { - public FixedWindowRateLimiterOptions(int permitLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit, System.TimeSpan window, bool autoReplenishment = true) { } - public bool AutoReplenishment { get { throw null; } } - public int PermitLimit { get { throw null; } } - public int QueueLimit { get { throw null; } } - public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } } - public System.TimeSpan Window { get { throw null; } } + public FixedWindowRateLimiterOptions() { } + public bool AutoReplenishment { get { throw null; } set { throw null; } } + public int PermitLimit { get { throw null; } set { throw null; } } + public int QueueLimit { get { throw null; } set { throw null; } } + public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } set { throw null; } } + public System.TimeSpan Window { get { throw null; } set { throw null; } } } public static partial class MetadataName { @@ -150,13 +150,13 @@ protected override void Dispose(bool disposing) { } } public sealed partial class SlidingWindowRateLimiterOptions { - public SlidingWindowRateLimiterOptions(int permitLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit, System.TimeSpan window, int segmentsPerWindow, bool autoReplenishment = true) { } - public bool AutoReplenishment { get { throw null; } } - public int PermitLimit { get { throw null; } } - public int QueueLimit { get { throw null; } } - public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } } - public int SegmentsPerWindow { get { throw null; } } - public System.TimeSpan Window { get { throw null; } } + public SlidingWindowRateLimiterOptions() { } + public bool AutoReplenishment { get { throw null; } set { throw null; } } + public int PermitLimit { get { throw null; } set { throw null; } } + public int QueueLimit { get { throw null; } set { throw null; } } + public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } set { throw null; } } + public int SegmentsPerWindow { get { throw null; } set { throw null; } } + public System.TimeSpan Window { get { throw null; } set { throw null; } } } public sealed partial class TokenBucketRateLimiter : System.Threading.RateLimiting.ReplenishingRateLimiter { @@ -173,12 +173,12 @@ protected override void Dispose(bool disposing) { } } public sealed partial class TokenBucketRateLimiterOptions { - public TokenBucketRateLimiterOptions(int tokenLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit, System.TimeSpan replenishmentPeriod, int tokensPerPeriod, bool autoReplenishment = true) { } - public bool AutoReplenishment { get { throw null; } } - public int QueueLimit { get { throw null; } } - public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } } - public System.TimeSpan ReplenishmentPeriod { get { throw null; } } - public int TokenLimit { get { throw null; } } - public int TokensPerPeriod { get { throw null; } } + public TokenBucketRateLimiterOptions() { } + public bool AutoReplenishment { get { throw null; } set { throw null; } } + public int QueueLimit { get { throw null; } set { throw null; } } + public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } set { throw null; } } + public System.TimeSpan ReplenishmentPeriod { get { throw null; } set { throw null; } } + public int TokenLimit { get { throw null; } set { throw null; } } + public int TokensPerPeriod { get { throw null; } set { throw null; } } } } From 136d7d499a9a2bce19492f4bd250206a5e9c1e6e Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 10:52:51 -0700 Subject: [PATCH 18/60] Update ChainedLimiterTests.cs --- .../tests/ChainedLimiterTests.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs index 20930f9a09101e..973c21688cbab2 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs @@ -44,11 +44,7 @@ public async Task DisposeMakesMethodsThrow() Assert.Throws(() => chainedLimiter.Acquire("")); await Assert.ThrowsAsync(async () => await chainedLimiter.WaitAndAcquireAsync("")); } -new StudentName - { - FirstName = "Craig", - LastName = "Playstead" - }; + [Fact] public async Task DisposeAsyncMakesMethodsThrow() { From 5be2a014ee97d009020725c895acb6cbc96c3200 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:25:34 -0700 Subject: [PATCH 19/60] Update ConcurrencyLimiter.cs --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index aef7c096448ba6..b18b2a220d2974 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -41,7 +41,7 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.PermitLimit <= 0 || options.QueueLimit <= 0) { - throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.QueueLimit)} must be set to values >= 0."); + throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.QueueLimit)} must be set to values greater than 0."); } _permitCount = _options.PermitLimit; } From efebe3ed6f41894bc5e3bd2ffd7938e555981f55 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:25:52 -0700 Subject: [PATCH 20/60] Update FixedWindowRateLimiter.cs --- .../src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 48ba8c9cff630f..bd4cd891db2be1 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -47,7 +47,7 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.Window.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, and {nameof(options.Window)} must all be set to values >= 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, and {nameof(options.Window)} must all be set to values greater than 0."); } _requestCount = options.PermitLimit; From aaac3fc0ae8cba5ac375cf31a1a9d45004dcdb3a Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:26:24 -0700 Subject: [PATCH 21/60] Update SlidingWindowRateLimiter.cs --- .../System/Threading/RateLimiting/SlidingWindowRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 3ef09cb7b99c6a..82847a0231bdfc 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -50,7 +50,7 @@ public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.SegmentsPerWindow <= 0 || options.Window.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values >= 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values greater than 0."); } _requestCount = options.PermitLimit; From 76380eaa826c43d9515a76db88ba5cf230ec4c3e Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:26:48 -0700 Subject: [PATCH 22/60] Update TokenBucketRateLimiter.cs --- .../src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 28a5474af89a46..a4624d9d81c71e 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -48,7 +48,7 @@ public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.TokenLimit <= 0 || options.QueueLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.QueueLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values >= 0."); + throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.QueueLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values greater than 0."); } _tokenCount = options.TokenLimit; From faa57854df1c9dfd8cab03bc3b22f5f62576b05d Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:27:21 -0700 Subject: [PATCH 23/60] Update ConcurrencyLimiterOptions.cs --- .../Threading/RateLimiting/ConcurrencyLimiterOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs index 6dfb625e1dcc9c..e69f4cb11bddb0 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class ConcurrencyLimiterOptions { /// /// Maximum number of permits that can be leased concurrently. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int PermitLimit { get; set; } @@ -24,7 +24,7 @@ public sealed class ConcurrencyLimiterOptions /// /// Maximum number of permits that can be queued concurrently. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From af59dd8927ec4c0410bbab912a50624d92e1b634 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:27:50 -0700 Subject: [PATCH 24/60] Update FixedWindowRateLimiterOptions.cs --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index 6f4dfa279d6dbc..c8aca6226fbd7f 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class FixedWindowRateLimiterOptions { /// /// Specifies the time window that takes in the requests. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a nonzero value by the time these options are passed to the constructor of . /// public TimeSpan Window { get; set; } = TimeSpan.Zero; @@ -25,7 +25,7 @@ public sealed class FixedWindowRateLimiterOptions /// /// Maximum number of permit counters that can be allowed in a window. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int PermitLimit { get; set; } @@ -39,7 +39,7 @@ public sealed class FixedWindowRateLimiterOptions /// /// Maximum cumulative permit count of queued acquisition requests. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From 1a8fbe013a98419e6c8c4690d093288189a1f021 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:28:19 -0700 Subject: [PATCH 25/60] Update SlidingWindowRateLimiterOptions.cs --- .../RateLimiting/SlidingWindowRateLimiterOptions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index bfb144017dc45d..1f3fc8b2b4a8f9 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -10,13 +10,13 @@ public sealed class SlidingWindowRateLimiterOptions { /// /// Specifies the minimum period between replenishments. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a nonzero value by the time these options are passed to the constructor of . /// public TimeSpan Window { get; set; } = TimeSpan.Zero; /// /// Specifies the maximum number of segments a window is divided into. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int SegmentsPerWindow { get; set; } @@ -31,7 +31,7 @@ public sealed class SlidingWindowRateLimiterOptions /// /// Maximum number of requests that can be served in a window. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int PermitLimit { get; set; } @@ -45,7 +45,7 @@ public sealed class SlidingWindowRateLimiterOptions /// /// Maximum cumulative permit count of queued acquisition requests. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From a252814993708ba8b686b9142525c11186c8cfef Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 11:28:55 -0700 Subject: [PATCH 26/60] Update ChainedLimiterTests.cs --- .../System.Threading.RateLimiting/tests/ChainedLimiterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs index 973c21688cbab2..2738b97f4bbb8d 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs @@ -56,7 +56,7 @@ public async Task DisposeAsyncMakesMethodsThrow() PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = 0 - }) + }); }); using var limiter2 = PartitionedRateLimiter.Create(resource => { From ae6202d22b0e546167a1a5a90083659a4423be0c Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 13:06:51 -0700 Subject: [PATCH 27/60] Update ChainedLimiterTests.cs --- .../tests/ChainedLimiterTests.cs | 152 +++++++++++++++--- 1 file changed, 133 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs index 2738b97f4bbb8d..d81fd019df1ca6 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs @@ -30,11 +30,23 @@ public async Task DisposeMakesMethodsThrow() { using var limiter1 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); using var limiter2 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter1, limiter2); @@ -60,7 +72,13 @@ public async Task DisposeAsyncMakesMethodsThrow() }); using var limiter2 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter1, limiter2); @@ -76,15 +94,33 @@ public void AvailablePermitsReturnsLowestValue() { using var limiter1 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(34, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 34, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); using var limiter2 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(22, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 22, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); using var limiter3 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(13, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 13, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); using var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter1, limiter2, limiter3); @@ -96,7 +132,13 @@ public void AvailablePermitsWithSingleLimiterWorks() { using var limiter = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, _ => new ConcurrencyLimiterOptions(34, QueueProcessingOrder.NewestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, _ => + new ConcurrencyLimiterOptions + { + PermitLimit = 34, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 0 + }); }); using var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter); @@ -451,7 +493,13 @@ internal sealed class ThrowDisposeLease : RateLimitLease [Fact] public void AcquireFailsDisposeThrows() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -472,7 +520,13 @@ public void AcquireFailsDisposeThrows() [Fact] public async Task WaitAndAcquireAsyncFailsDisposeThrows() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -493,7 +547,13 @@ public async Task WaitAndAcquireAsyncFailsDisposeThrows() [Fact] public void AcquireFailsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -519,7 +579,13 @@ public void AcquireFailsDisposeThrowsMultipleLimitersThrow() [Fact] public async Task WaitAndAcquireAsyncFailsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -545,7 +611,13 @@ public async Task WaitAndAcquireAsyncFailsDisposeThrowsMultipleLimitersThrow() [Fact] public void AcquireThrowsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -572,7 +644,13 @@ public void AcquireThrowsDisposeThrowsMultipleLimitersThrow() [Fact] public async Task WaitAndAcquireAsyncThrowsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -599,7 +677,13 @@ public async Task WaitAndAcquireAsyncThrowsDisposeThrowsMultipleLimitersThrow() [Fact] public void AcquireSucceedsDisposeThrowsAndReleasesResources() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -623,7 +707,13 @@ public void AcquireSucceedsDisposeThrowsAndReleasesResources() [Fact] public async Task WaitAndAcquireAsyncSucceedsDisposeThrowsAndReleasesResources() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -647,8 +737,20 @@ public async Task WaitAndAcquireAsyncSucceedsDisposeThrowsAndReleasesResources() [Fact] public void AcquireForwardsCorrectPermitCount() { - using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(5, QueueProcessingOrder.OldestFirst, 0)); - using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(3, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter1 = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 5, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -672,8 +774,20 @@ public void AcquireForwardsCorrectPermitCount() [Fact] public async Task WaitAndAcquireAsyncForwardsCorrectPermitCount() { - using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(5, QueueProcessingOrder.OldestFirst, 0)); - using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(3, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter1 = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 5, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter( + new ConcurrencyLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); From c79b34be263947d293dbf26ee4a62b368df87503 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Wed, 20 Jul 2022 15:21:50 -0700 Subject: [PATCH 28/60] Fix tests --- .../tests/ChainedLimiterTests.cs | 289 +++++---- .../tests/ConcurrencyLimiterTests.cs | 266 +++++++-- .../tests/FixedWindowRateLimiterTests.cs | 438 +++++++++++--- .../tests/PartitionedRateLimiterTests.cs | 54 +- .../tests/RateLimiterPartitionTests.cs | 53 +- .../tests/SlidingWindowRateLimiterTests.cs | 470 ++++++++++++--- .../tests/TokenBucketRateLimiterTests.cs | 547 ++++++++++++++---- 7 files changed, 1698 insertions(+), 419 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs index d81fd019df1ca6..b5dbd18c781c5a 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs @@ -232,8 +232,18 @@ public async Task WaitAndAcquireAsyncWorksWithMultipleLimiters() [Fact] public void AcquireLeaseCorrectlyDisposesWithMultipleLimiters() { - var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); - var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -258,8 +268,18 @@ public void AcquireLeaseCorrectlyDisposesWithMultipleLimiters() [Fact] public async Task WaitAndAcquireAsyncLeaseCorrectlyDisposesWithMultipleLimiters() { - var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); - var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -284,7 +304,12 @@ public async Task WaitAndAcquireAsyncLeaseCorrectlyDisposesWithMultipleLimiters( [Fact] public void AcquireLeaseCorrectlyDisposesWithSingleLimiter() { - var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter); @@ -303,7 +328,12 @@ public void AcquireLeaseCorrectlyDisposesWithSingleLimiter() [Fact] public async Task WaitAndAcquireAsyncLeaseCorrectlyDisposesWithSingleLimiter() { - var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter); @@ -323,7 +353,12 @@ public async Task WaitAndAcquireAsyncLeaseCorrectlyDisposesWithSingleLimiter() public void AcquireFailsWhenOneLimiterDoesNotHaveEnoughResources() { var limiterFactory = new TrackingRateLimiterFactory(); - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)); @@ -349,7 +384,12 @@ public void AcquireFailsWhenOneLimiterDoesNotHaveEnoughResources() public async Task WaitAndAcquireAsyncFailsWhenOneLimiterDoesNotHaveEnoughResources() { var limiterFactory = new TrackingRateLimiterFactory(); - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)); @@ -374,8 +414,18 @@ public async Task WaitAndAcquireAsyncFailsWhenOneLimiterDoesNotHaveEnoughResourc [Fact] public void AcquireFailsAndReleasesAcquiredResources() { - using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); - using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -398,8 +448,18 @@ public void AcquireFailsAndReleasesAcquiredResources() [Fact] public async Task WaitAndAcquireAsyncFailsAndReleasesAcquiredResources() { - using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); - using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -422,7 +482,12 @@ public async Task WaitAndAcquireAsyncFailsAndReleasesAcquiredResources() [Fact] public void AcquireThrowsAndReleasesAcquiredResources() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter); @@ -440,7 +505,12 @@ public void AcquireThrowsAndReleasesAcquiredResources() [Fact] public async Task WaitAndAcquireAsyncThrowsAndReleasesAcquiredResources() { - using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter); @@ -493,13 +563,12 @@ internal sealed class ThrowDisposeLease : RateLimitLease [Fact] public void AcquireFailsDisposeThrows() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -520,13 +589,12 @@ public void AcquireFailsDisposeThrows() [Fact] public async Task WaitAndAcquireAsyncFailsDisposeThrows() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -547,13 +615,12 @@ public async Task WaitAndAcquireAsyncFailsDisposeThrows() [Fact] public void AcquireFailsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -579,13 +646,12 @@ public void AcquireFailsDisposeThrowsMultipleLimitersThrow() [Fact] public async Task WaitAndAcquireAsyncFailsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -611,13 +677,12 @@ public async Task WaitAndAcquireAsyncFailsDisposeThrowsMultipleLimitersThrow() [Fact] public void AcquireThrowsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -644,13 +709,12 @@ public void AcquireThrowsDisposeThrowsMultipleLimitersThrow() [Fact] public async Task WaitAndAcquireAsyncThrowsDisposeThrowsMultipleLimitersThrow() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -677,13 +741,12 @@ public async Task WaitAndAcquireAsyncThrowsDisposeThrowsMultipleLimitersThrow() [Fact] public void AcquireSucceedsDisposeThrowsAndReleasesResources() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() }); @@ -707,13 +770,12 @@ public void AcquireSucceedsDisposeThrowsAndReleasesResources() [Fact] public async Task WaitAndAcquireAsyncSucceedsDisposeThrowsAndReleasesResources() { - using var concurrencyLimiter = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 1, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask(new ThrowDisposeLease()) }); @@ -737,20 +799,18 @@ public async Task WaitAndAcquireAsyncSucceedsDisposeThrowsAndReleasesResources() [Fact] public void AcquireForwardsCorrectPermitCount() { - using var concurrencyLimiter1 = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 5, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); - using var concurrencyLimiter2 = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 3, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 5, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -774,20 +834,18 @@ public void AcquireForwardsCorrectPermitCount() [Fact] public async Task WaitAndAcquireAsyncForwardsCorrectPermitCount() { - using var concurrencyLimiter1 = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 5, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); - using var concurrencyLimiter2 = new ConcurrencyLimiter( - new ConcurrencyLimiterOptions - { - PermitLimit = 3, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 0 - }); + using var concurrencyLimiter1 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 5, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + using var concurrencyLimiter2 = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter1); @@ -871,7 +929,12 @@ public async Task WaitAndAcquireAsyncCanBeCanceled() { using var limiter = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); }); using var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter); @@ -888,14 +951,24 @@ public async Task WaitAndAcquireAsyncCanBeCanceled() [Fact] public async Task WaitAndAcquireAsyncCanceledReleasesAcquiredResources() { - var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.OldestFirst, 0)); + var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); using var limiter1 = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.Get(1, key => concurrencyLimiter); }); using var limiter2 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); }); using var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter1, limiter2); @@ -917,13 +990,23 @@ public async Task WaitAndAcquireAsyncWaitsForResourcesBeforeCallingNextLimiter() { using var limiter1 = PartitionedRateLimiter.Create(resource => { - return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); }); using var limiter2 = PartitionedRateLimiter.Create(resource => { // 0 queue limit to verify this isn't called while the previous limiter is waiting for resource(s) // as it would return a failed lease when no queue is available - return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 0)); + return RateLimitPartition.GetConcurrencyLimiter(1, key => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); }); using var chainedLimiter = PartitionedRateLimiter.CreateChained(limiter1, limiter2); diff --git a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs index bd65b91d70f546..aa38aa2d53a1e4 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs @@ -11,14 +11,29 @@ public class ConcurrencyLimiterTests : BaseRateLimiterTests [Fact] public override void InvalidOptionsThrows() { - Assert.Throws(() => new ConcurrencyLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1)); - Assert.Throws(() => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1)); + Assert.Throws(() => new ConcurrencyLimiterOptions + { + PermitLimit = -1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); + Assert.Throws(() => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = -1 + }); } [Fact] public override void CanAcquireResource() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(); Assert.True(lease.IsAcquired); @@ -32,7 +47,12 @@ public override void CanAcquireResource() [Fact] public override async Task CanAcquireResourceAsync() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var lease = await limiter.WaitAndAcquireAsync(); Assert.True(lease.IsAcquired); @@ -47,7 +67,12 @@ public override async Task CanAcquireResourceAsync() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2 + }); var lease = await limiter.WaitAndAcquireAsync(); Assert.True(lease.IsAcquired); @@ -71,7 +96,12 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3 + }); var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -96,7 +126,12 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() [Fact] public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -107,7 +142,12 @@ public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() [Fact] public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); Assert.False(wait.IsCompleted); @@ -126,7 +166,12 @@ public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() [Fact] public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2 + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); var wait = limiter.WaitAndAcquireAsync(1); @@ -151,7 +196,12 @@ public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFir [Fact] public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -170,7 +220,12 @@ public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimit [Fact] public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = int.MaxValue, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = int.MaxValue + }); var lease = limiter.Acquire(int.MaxValue); Assert.True(lease.IsAcquired); @@ -192,7 +247,12 @@ public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() [Fact] public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -214,7 +274,12 @@ public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAv [Fact] public override void ThrowsWhenAcquiringMoreThanLimit() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var ex = Assert.Throws(() => limiter.Acquire(2)); Assert.Equal("permitCount", ex.ParamName); } @@ -222,7 +287,12 @@ public override void ThrowsWhenAcquiringMoreThanLimit() [Fact] public override async Task ThrowsWhenWaitingForMoreThanLimit() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var ex = await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(2)); Assert.Equal("permitCount", ex.ParamName); } @@ -230,21 +300,36 @@ public override async Task ThrowsWhenWaitingForMoreThanLimit() [Fact] public override void ThrowsWhenAcquiringLessThanZero() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); Assert.Throws(() => limiter.Acquire(-1)); } [Fact] public override async Task ThrowsWhenWaitingForLessThanZero() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(-1)); } [Fact] public override void AcquireZero_WithAvailability() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(0); Assert.True(lease.IsAcquired); @@ -253,7 +338,12 @@ public override void AcquireZero_WithAvailability() [Fact] public override void AcquireZero_WithoutAvailability() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -265,7 +355,12 @@ public override void AcquireZero_WithoutAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithAvailability() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); using var lease = await limiter.WaitAndAcquireAsync(0); Assert.True(lease.IsAcquired); @@ -274,7 +369,12 @@ public override async Task WaitAndAcquireAsyncZero_WithAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAvailability() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -289,7 +389,12 @@ public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAv [Fact] public override async Task CanDequeueMultipleResourcesAtOnce() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.OldestFirst, 2)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -309,7 +414,12 @@ public override async Task CanDequeueMultipleResourcesAtOnce() [Fact] public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfNewestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3 + }); using var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -331,7 +441,12 @@ public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedI [Fact] public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfOldestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3 + }); using var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -354,7 +469,12 @@ public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueu [Fact] public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3 + }); using var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -375,7 +495,12 @@ public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewest [Fact] public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOldestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3 + }); using var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -393,7 +518,12 @@ public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOld [Fact] public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -412,7 +542,12 @@ public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() [Fact] public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -430,7 +565,12 @@ public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() [Fact] public override async Task CancelUpdatesQueueLimit() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -452,7 +592,12 @@ public override async Task CancelUpdatesQueueLimit() [Fact] public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedRequestWithAnotherQueuedRequest() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2 + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -483,7 +628,12 @@ public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedReques [Fact] public override async Task CanDisposeAfterCancelingQueuedRequest() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -501,7 +651,12 @@ public override async Task CanDisposeAfterCancelingQueuedRequest() [Fact] public override void NoMetadataOnAcquiredLease() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(1); Assert.False(lease.TryGetMetadata(MetadataName.ReasonPhrase.Name, out _)); } @@ -509,7 +664,12 @@ public override void NoMetadataOnAcquiredLease() [Fact] public override void MetadataNamesContainsAllMetadata() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(1); Assert.Collection(lease.MetadataNames, metadataName => Assert.Equal(metadataName, MetadataName.ReasonPhrase.Name)); } @@ -517,7 +677,12 @@ public override void MetadataNamesContainsAllMetadata() [Fact] public override async Task DisposeReleasesQueuedAcquires() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3 + }); using var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); @@ -546,7 +711,12 @@ public override async Task DisposeReleasesQueuedAcquires() [Fact] public override async Task DisposeAsyncReleasesQueuedAcquires() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3 + }); using var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); @@ -575,7 +745,12 @@ public override async Task DisposeAsyncReleasesQueuedAcquires() [Fact] public async Task ReasonMetadataOnFailedWaitAsync() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(2); var failedLease = await limiter.WaitAndAcquireAsync(2); @@ -591,7 +766,12 @@ public async Task ReasonMetadataOnFailedWaitAsync() [Fact] public override void NullIdleDurationWhenActive() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); using var lease = limiter.Acquire(1); Assert.Null(limiter.IdleDuration); } @@ -599,7 +779,12 @@ public override void NullIdleDurationWhenActive() [Fact] public override async Task IdleDurationUpdatesWhenIdle() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); Assert.NotNull(limiter.IdleDuration); var previousDuration = limiter.IdleDuration; await Task.Delay(15); @@ -609,7 +794,12 @@ public override async Task IdleDurationUpdatesWhenIdle() [Fact] public override void IdleDurationUpdatesWhenChangingFromActive() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1 + }); var lease = limiter.Acquire(1); lease.Dispose(); Assert.NotNull(limiter.IdleDuration); diff --git a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs index 0c0063a5aff031..400b47d9bd9c00 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs @@ -12,8 +12,14 @@ public class FixedWindowRateLimiterTests : BaseRateLimiterTests [Fact] public override void CanAcquireResource() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(); Assert.True(lease.IsAcquired); @@ -30,16 +36,36 @@ public override void CanAcquireResource() public override void InvalidOptionsThrows() { Assert.Throws( - () => new FixedWindowRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), autoReplenishment: false)); + () => new FixedWindowRateLimiterOptions + { + PermitLimit = -1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMinutes(2), + AutoReplenishment = false + }); Assert.Throws( - () => new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), autoReplenishment: false)); + () => new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = -1, + Window = TimeSpan.FromMinutes(2), + AutoReplenishment = false + }); } [Fact] public override async Task CanAcquireResourceAsync() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(); @@ -55,8 +81,14 @@ public override async Task CanAcquireResourceAsync() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(); Assert.True(lease.IsAcquired); @@ -83,8 +115,14 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.FromMinutes(0), autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + Window = TimeSpan.FromMinutes(0), + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -113,8 +151,14 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() [Fact] public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -127,8 +171,14 @@ public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() [Fact] public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); Assert.False(wait.IsCompleted); @@ -147,8 +197,14 @@ public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() [Fact] public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); var wait = limiter.WaitAndAcquireAsync(1); @@ -173,8 +229,14 @@ public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFir [Fact] public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -194,8 +256,14 @@ public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimit [Fact] public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -217,8 +285,14 @@ public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAv [Fact] public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = int.MaxValue, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = int.MaxValue, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(int.MaxValue); Assert.True(lease.IsAcquired); @@ -240,40 +314,70 @@ public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() [Fact] public override void ThrowsWhenAcquiringMoreThanLimit() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(2)); } [Fact] public override async Task ThrowsWhenWaitingForMoreThanLimit() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(2)); } [Fact] public override void ThrowsWhenAcquiringLessThanZero() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(-1)); } [Fact] public override async Task ThrowsWhenWaitingForLessThanZero() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(-1)); } [Fact] public override void AcquireZero_WithAvailability() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = limiter.Acquire(0); Assert.True(lease.IsAcquired); @@ -282,8 +386,14 @@ public override void AcquireZero_WithAvailability() [Fact] public override void AcquireZero_WithoutAvailability() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -295,8 +405,14 @@ public override void AcquireZero_WithoutAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithAvailability() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(0); Assert.True(lease.IsAcquired); @@ -305,8 +421,14 @@ public override async Task WaitAndAcquireAsyncZero_WithAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAvailability() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -322,8 +444,14 @@ public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAv [Fact] public override async Task CanDequeueMultipleResourcesAtOnce() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -344,8 +472,14 @@ public override async Task CanDequeueMultipleResourcesAtOnce() [Fact] public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -365,8 +499,14 @@ public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() [Fact] public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -385,8 +525,14 @@ public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() [Fact] public override async Task CancelUpdatesQueueLimit() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -408,8 +554,14 @@ public override async Task CancelUpdatesQueueLimit() [Fact] public override void NoMetadataOnAcquiredLease() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.False(lease.TryGetMetadata(MetadataName.RetryAfter, out _)); } @@ -417,8 +569,14 @@ public override void NoMetadataOnAcquiredLease() [Fact] public override void MetadataNamesContainsAllMetadata() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.Collection(lease.MetadataNames, metadataName => Assert.Equal(metadataName, MetadataName.RetryAfter.Name)); } @@ -426,8 +584,14 @@ public override void MetadataNamesContainsAllMetadata() [Fact] public override async Task DisposeReleasesQueuedAcquires() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -453,8 +617,14 @@ public override async Task DisposeReleasesQueuedAcquires() [Fact] public override async Task DisposeAsyncReleasesQueuedAcquires() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -480,8 +650,14 @@ public override async Task DisposeAsyncReleasesQueuedAcquires() [Fact] public async Task RetryMetadataOnFailedWaitAsync() { - var options = new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), autoReplenishment: false); + 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.Acquire(2); @@ -500,8 +676,14 @@ public async Task RetryMetadataOnFailedWaitAsync() [Fact] public async Task CorrectRetryMetadataWithQueuedItem() { - var options = new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), autoReplenishment: false); + 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.Acquire(2); @@ -519,8 +701,14 @@ public async Task CorrectRetryMetadataWithQueuedItem() [Fact] public async Task CorrectRetryMetadataWithNonZeroAvailableItems() { - var options = new FixedWindowRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), autoReplenishment: false); + var options = new FixedWindowRateLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + AutoReplenishment = false + }; var limiter = new FixedWindowRateLimiter(options); using var lease = limiter.Acquire(2); @@ -534,8 +722,14 @@ public async Task CorrectRetryMetadataWithNonZeroAvailableItems() [Fact] public void TryReplenishWithAutoReplenish_ReturnsFalse() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(1), autoReplenishment: true)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(1), + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); Assert.False(limiter.TryReplenish()); Assert.Equal(2, limiter.GetAvailablePermits()); @@ -544,8 +738,14 @@ public void TryReplenishWithAutoReplenish_ReturnsFalse() [Fact] public async Task AutoReplenish_ReplenishesCounters() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromMilliseconds(1000), autoReplenishment: true)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMilliseconds(1000), + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); limiter.Acquire(2); @@ -556,8 +756,14 @@ public async Task AutoReplenish_ReplenishesCounters() [Fact] public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfNewestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -579,8 +785,14 @@ public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedI [Fact] public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfOldestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -605,8 +817,14 @@ public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueu [Fact] public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -627,8 +845,14 @@ public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewest [Fact] public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOldestFirst() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -648,8 +872,14 @@ public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOld [Fact] public override void NullIdleDurationWhenActive() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.FromMilliseconds(2), + AutoReplenishment = false + }); limiter.Acquire(1); Assert.Null(limiter.IdleDuration); } @@ -657,8 +887,14 @@ public override void NullIdleDurationWhenActive() [Fact] public override async Task IdleDurationUpdatesWhenIdle() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.FromMilliseconds(2), + AutoReplenishment = false + }); Assert.NotNull(limiter.IdleDuration); var previousDuration = limiter.IdleDuration; await Task.Delay(15); @@ -668,8 +904,14 @@ public override async Task IdleDurationUpdatesWhenIdle() [Fact] public override void IdleDurationUpdatesWhenChangingFromActive() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); limiter.Acquire(1); limiter.TryReplenish(); Assert.NotNull(limiter.IdleDuration); @@ -679,14 +921,26 @@ public override void IdleDurationUpdatesWhenChangingFromActive() public void ReplenishingRateLimiterPropertiesHaveCorrectValues() { var replenishPeriod = TimeSpan.FromMinutes(1); - using ReplenishingRateLimiter limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, autoReplenishment: true)); + using ReplenishingRateLimiter limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = replenishPeriod, + AutoReplenishment = true + }); Assert.True(limiter.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter.ReplenishmentPeriod); replenishPeriod = TimeSpan.FromSeconds(2); - using ReplenishingRateLimiter limiter2 = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, autoReplenishment: false)); + using ReplenishingRateLimiter limiter2 = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = replenishPeriod, + AutoReplenishment = false + }); Assert.False(limiter2.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter2.ReplenishmentPeriod); } @@ -694,8 +948,14 @@ public void ReplenishingRateLimiterPropertiesHaveCorrectValues() [Fact] public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedRequestWithAnotherQueuedRequest() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -727,8 +987,14 @@ public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedReques [Fact] public override async Task CanDisposeAfterCancelingQueuedRequest() { - var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, autoReplenishment: false)); + var limiter = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); diff --git a/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs index e99b603b08bb66..5fe7e70befce26 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs @@ -133,7 +133,12 @@ public async Task Create_BlockingWaitDoesNotBlockOtherPartitions() return RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key)); } return RateLimitPartition.GetConcurrencyLimiter(2, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2 + }); }); var lease = await limiter.WaitAndAcquireAsync("2"); @@ -370,7 +375,15 @@ public async Task Create_WithTokenBucketReplenishesAutomatically() using var limiter = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.GetTokenBucketLimiter(1, - _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)); + _ => new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(100), + TokensPerPeriod = 1, + AutoReplenishment = false + }); }); var lease = limiter.Acquire(""); @@ -387,7 +400,15 @@ public async Task Create_WithReplenishingLimiterReplenishesAutomatically() { // Use the non-specific Create method to make sure ReplenishingRateLimiters are still handled properly return RateLimitPartition.Get(1, - _ => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false))); + _ => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(100), + TokensPerPeriod = 1, + AutoReplenishment = false + })); }); var lease = limiter.Acquire(""); @@ -405,10 +426,26 @@ public async Task Create_MultipleReplenishingLimitersReplenishAutomatically() if (resource == "1") { return RateLimitPartition.GetTokenBucketLimiter(1, - _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)); + _ => new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(100), + TokensPerPeriod = 1, + AutoReplenishment = false + }); } return RateLimitPartition.GetTokenBucketLimiter(2, - _ => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMilliseconds(100), 1, false)); + _ => new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(100), + TokensPerPeriod = 1, + AutoReplenishment = false + }); }); var lease = limiter.Acquire("1"); @@ -434,7 +471,12 @@ public async Task Create_CancellationTokenPassedToUnderlyingLimiter() using var limiter = PartitionedRateLimiter.Create(resource => { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); }); var lease = limiter.Acquire(""); diff --git a/src/libraries/System.Threading.RateLimiting/tests/RateLimiterPartitionTests.cs b/src/libraries/System.Threading.RateLimiting/tests/RateLimiterPartitionTests.cs index 4987ab3186bedd..be797b1feba498 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/RateLimiterPartitionTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/RateLimiterPartitionTests.cs @@ -11,7 +11,12 @@ public class RateLimiterPartitionTests [Fact] public void Create_Concurrency() { - var options = new ConcurrencyLimiterOptions(10, QueueProcessingOrder.OldestFirst, 10); + var options = new ConcurrencyLimiterOptions + { + PermitLimit = 10, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 10 + }; var partition = RateLimitPartition.GetConcurrencyLimiter(1, key => options); var limiter = partition.Factory(1); @@ -22,7 +27,15 @@ public void Create_Concurrency() [Fact] public void Create_TokenBucket() { - var options = new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromMinutes(1), 1, true); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 10, + ReplenishmentPeriod = TimeSpan.FromMinutes(1), + TokensPerPeriod = 1, + AutoReplenishment = true + }; var partition = RateLimitPartition.GetTokenBucketLimiter(1, key => options); var limiter = partition.Factory(1); @@ -59,13 +72,26 @@ public async Task Create_NoLimiter() [Fact] public void Create_AnyLimiter() { - var partition = RateLimitPartition.Get(1, key => new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10))); + 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(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))); + 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(limiter); Assert.Equal(1, tokenBucketLimiter.GetAvailablePermits()); @@ -74,7 +100,14 @@ public void Create_AnyLimiter() [Fact] public void Create_FixedWindow() { - var options = new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromMinutes(1), true); + var options = new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 10, + Window = TimeSpan.FromMinutes(1), + AutoReplenishment = true + }; var partition = RateLimitPartition.GetFixedWindowLimiter(1, key => options); var limiter = partition.Factory(1); @@ -87,7 +120,15 @@ public void Create_FixedWindow() [Fact] public void Create_SlidingWindow() { - var options = new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 10, TimeSpan.FromSeconds(33), 3, true); + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 10, + Window = TimeSpan.FromSeconds(33), + SegmentsPerWindow = 3, + AutoReplenishment = true + }; var partition = RateLimitPartition.GetSlidingWindowLimiter(1, key => options); var limiter = partition.Factory(1); diff --git a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs index ff838e9a44e863..71f66ea71bc573 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs @@ -12,8 +12,15 @@ public class SlidingWindowRateLimiterTests : BaseRateLimiterTests [Fact] public override void CanAcquireResource() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(); Assert.True(lease.IsAcquired); @@ -31,18 +38,49 @@ public override void CanAcquireResource() public override void InvalidOptionsThrows() { Assert.Throws( - () => new SlidingWindowRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false)); + () => new SlidingWindowRateLimiterOptions + { + PermitLimit = -1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMinutes(2), + SegmentsPerWindow = 1, + AutoReplenishment = false + }); Assert.Throws( - () => new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false)); + () => new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = -1, + Window = TimeSpan.FromMinutes(2), + SegmentsPerWindow = 1, + AutoReplenishment = false + }); Assert.Throws( - () => new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), -1, autoReplenishment: false)); + () => new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMinutes(2), + SegmentsPerWindow = -1, + AutoReplenishment = false + }); } [Fact] public override async Task CanAcquireResourceAsync() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 4, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 4, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(); @@ -68,8 +106,15 @@ public async Task CanAcquireMultipleRequestsAsync() // This test verifies the following behavior // 1. when we have available permits after replenish to serve the queued requests // 2. when the oldest item from queue is remove to accommodate new requests (QueueProcessingOrder: NewestFirst) - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(4, QueueProcessingOrder.NewestFirst, 4, - TimeSpan.Zero, 3, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 4, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 4, + Window = TimeSpan.Zero, + SegmentsPerWindow = 3, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(2); @@ -99,8 +144,15 @@ public async Task CanAcquireMultipleRequestsAsync() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.FromMinutes(0), 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.FromMinutes(0), + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -131,8 +183,15 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.FromMinutes(0), 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + Window = TimeSpan.FromMinutes(0), + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -164,8 +223,15 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() [Fact] public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -176,8 +242,15 @@ public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() [Fact] public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); Assert.False(wait.IsCompleted); @@ -197,8 +270,15 @@ public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() [Fact] public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); var wait = limiter.WaitAndAcquireAsync(1); @@ -224,8 +304,15 @@ public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFir [Fact] public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -246,8 +333,15 @@ public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimit [Fact] public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, 3, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + SegmentsPerWindow = 3, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); var wait = limiter.WaitAndAcquireAsync(2); @@ -276,8 +370,15 @@ public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAv [Fact] public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = int.MaxValue, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = int.MaxValue, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(int.MaxValue); Assert.True(lease.IsAcquired); @@ -300,40 +401,75 @@ public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() [Fact] public override void ThrowsWhenAcquiringMoreThanLimit() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(2)); } [Fact] public override async Task ThrowsWhenWaitingForMoreThanLimit() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(2)); } [Fact] public override void ThrowsWhenAcquiringLessThanZero() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(-1)); } [Fact] public override async Task ThrowsWhenWaitingForLessThanZero() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(-1)); } [Fact] public override void AcquireZero_WithAvailability() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(0); Assert.True(lease.IsAcquired); @@ -342,8 +478,15 @@ public override void AcquireZero_WithAvailability() [Fact] public override void AcquireZero_WithoutAvailability() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -355,8 +498,15 @@ public override void AcquireZero_WithoutAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithAvailability() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(0); Assert.True(lease.IsAcquired); @@ -365,8 +515,15 @@ public override async Task WaitAndAcquireAsyncZero_WithAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAvailability() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -383,8 +540,15 @@ public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAv [Fact] public override async Task CanDequeueMultipleResourcesAtOnce() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 4, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 4, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -406,8 +570,15 @@ public override async Task CanDequeueMultipleResourcesAtOnce() [Fact] public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -427,8 +598,15 @@ public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() [Fact] public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -447,8 +625,15 @@ public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() [Fact] public override async Task CancelUpdatesQueueLimit() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -473,8 +658,15 @@ public override async Task CancelUpdatesQueueLimit() [Fact] public override void NoMetadataOnAcquiredLease() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.False(lease.TryGetMetadata(MetadataName.RetryAfter, out _)); } @@ -482,8 +674,15 @@ public override void NoMetadataOnAcquiredLease() [Fact] public override void MetadataNamesContainsAllMetadata() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.Collection(lease.MetadataNames, metadataName => Assert.Equal(metadataName, MetadataName.RetryAfter.Name)); } @@ -491,8 +690,15 @@ public override void MetadataNamesContainsAllMetadata() [Fact] public override async Task DisposeReleasesQueuedAcquires() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -518,8 +724,15 @@ public override async Task DisposeReleasesQueuedAcquires() [Fact] public override async Task DisposeAsyncReleasesQueuedAcquires() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -545,8 +758,15 @@ public override async Task DisposeAsyncReleasesQueuedAcquires() [Fact] public void TryReplenishWithAutoReplenish_ReturnsFalse() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(1), 1, autoReplenishment: true)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(1), + SegmentsPerWindow = 1, + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); Assert.False(limiter.TryReplenish()); Assert.Equal(2, limiter.GetAvailablePermits()); @@ -555,8 +775,15 @@ public void TryReplenishWithAutoReplenish_ReturnsFalse() [Fact] public async Task AutoReplenish_ReplenishesCounters() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromMilliseconds(1000), 2, autoReplenishment: true)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMilliseconds(1000), + SegmentsPerWindow = 2, + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); limiter.Acquire(2); @@ -567,8 +794,15 @@ public async Task AutoReplenish_ReplenishesCounters() [Fact] public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfNewestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 3, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + SegmentsPerWindow = 3, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -594,8 +828,15 @@ public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedI [Fact] public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfOldestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 5, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 5, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(3); Assert.True(lease.IsAcquired); @@ -625,8 +866,15 @@ public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueu [Fact] public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -648,8 +896,15 @@ public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewest [Fact] public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOldestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -670,8 +925,15 @@ public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOld [Fact] public override void NullIdleDurationWhenActive() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), 1, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.FromMilliseconds(2), + SegmentsPerWindow = 1, + AutoReplenishment = false + }); limiter.Acquire(1); Assert.Null(limiter.IdleDuration); } @@ -679,8 +941,15 @@ public override void NullIdleDurationWhenActive() [Fact] public override async Task IdleDurationUpdatesWhenIdle() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.FromMilliseconds(2), + SegmentsPerWindow = 2, + AutoReplenishment = false + }); Assert.NotNull(limiter.IdleDuration); var previousDuration = limiter.IdleDuration; await Task.Delay(15); @@ -690,8 +959,15 @@ public override async Task IdleDurationUpdatesWhenIdle() [Fact] public override void IdleDurationUpdatesWhenChangingFromActive() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); limiter.Acquire(1); limiter.TryReplenish(); limiter.TryReplenish(); @@ -702,14 +978,28 @@ public override void IdleDurationUpdatesWhenChangingFromActive() public void ReplenishingRateLimiterPropertiesHaveCorrectValues() { var replenishPeriod = TimeSpan.FromMinutes(1); - using ReplenishingRateLimiter limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, 1, autoReplenishment: true)); + using ReplenishingRateLimiter limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = replenishPeriod, + SegmentsPerWindow = 1, + AutoReplenishment = true + }); Assert.True(limiter.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter.ReplenishmentPeriod); replenishPeriod = TimeSpan.FromSeconds(2); - using ReplenishingRateLimiter limiter2 = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, 1, autoReplenishment: false)); + using ReplenishingRateLimiter limiter2 = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + Window = replenishPeriod, + SegmentsPerWindow = 1, + AutoReplenishment = false + }); Assert.False(limiter2.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter2.ReplenishmentPeriod); } @@ -717,8 +1007,15 @@ public void ReplenishingRateLimiterPropertiesHaveCorrectValues() [Fact] public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedRequestWithAnotherQueuedRequest() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -751,8 +1048,15 @@ public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedReques [Fact] public override async Task CanDisposeAfterCancelingQueuedRequest() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.Zero, + SegmentsPerWindow = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); diff --git a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs index 14232bf61eee94..e125a0c2a5327e 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs @@ -12,8 +12,15 @@ public class TokenBucketRateLimiterTests : BaseRateLimiterTests [Fact] public override void CanAcquireResource() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(); Assert.True(lease.IsAcquired); @@ -30,18 +37,49 @@ public override void CanAcquireResource() public override void InvalidOptionsThrows() { Assert.Throws( - () => new TokenBucketRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false)); + () => new TokenBucketRateLimiterOptions + { + TokenLimit = -1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMinutes(2), + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.Throws( - () => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false)); + () => new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = -1, + ReplenishmentPeriod = TimeSpan.FromMinutes(2), + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.Throws( - () => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), -1, autoReplenishment: false)); + () => new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMinutes(2), + TokensPerPeriod = -1, + AutoReplenishment = false + }); } [Fact] public override async Task CanAcquireResourceAsync() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(); @@ -57,8 +95,15 @@ public override async Task CanAcquireResourceAsync() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(); Assert.True(lease.IsAcquired); @@ -85,8 +130,15 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsOldest() [Fact] public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.FromMinutes(0), 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.FromMinutes(0), + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -116,8 +168,15 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() [Fact] public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -130,8 +189,15 @@ public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() [Fact] public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); Assert.False(wait.IsCompleted); @@ -150,8 +216,15 @@ public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() [Fact] public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); var wait = limiter.WaitAndAcquireAsync(1); @@ -177,8 +250,15 @@ public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFir [Fact] public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -198,8 +278,15 @@ public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimit [Fact] public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait = limiter.WaitAndAcquireAsync(1); @@ -221,8 +308,15 @@ public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAv [Fact] public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue, - TimeSpan.Zero, int.MaxValue, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = int.MaxValue, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = int.MaxValue, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = int.MaxValue, + AutoReplenishment = false + }); var lease = limiter.Acquire(int.MaxValue); Assert.True(lease.IsAcquired); @@ -244,40 +338,75 @@ public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() [Fact] public override void ThrowsWhenAcquiringMoreThanLimit() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(2)); } [Fact] public override async Task ThrowsWhenWaitingForMoreThanLimit() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(2)); } [Fact] public override void ThrowsWhenAcquiringLessThanZero() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.Throws(() => limiter.Acquire(-1)); } [Fact] public override async Task ThrowsWhenWaitingForLessThanZero() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); await Assert.ThrowsAsync(async () => await limiter.WaitAndAcquireAsync(-1)); } [Fact] public override void AcquireZero_WithAvailability() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(0); Assert.True(lease.IsAcquired); @@ -286,8 +415,15 @@ public override void AcquireZero_WithAvailability() [Fact] public override void AcquireZero_WithoutAvailability() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -299,8 +435,15 @@ public override void AcquireZero_WithoutAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithAvailability() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(0); Assert.True(lease.IsAcquired); @@ -309,8 +452,15 @@ public override async Task WaitAndAcquireAsyncZero_WithAvailability() [Fact] public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAvailability() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = await limiter.WaitAndAcquireAsync(1); Assert.True(lease.IsAcquired); @@ -326,8 +476,15 @@ public override async Task WaitAndAcquireAsyncZero_WithoutAvailabilityWaitsForAv [Fact] public override async Task CanDequeueMultipleResourcesAtOnce() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); using var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); @@ -348,8 +505,15 @@ public override async Task CanDequeueMultipleResourcesAtOnce() [Fact] public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -369,8 +533,15 @@ public override async Task CanCancelWaitAndAcquireAsyncAfterQueuing() [Fact] public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedRequestWithAnotherQueuedRequest() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(2); Assert.True(lease.IsAcquired); @@ -402,8 +573,15 @@ public override async Task CanFillQueueWithNewestFirstAfterCancelingQueuedReques [Fact] public override async Task CanDisposeAfterCancelingQueuedRequest() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -421,8 +599,15 @@ public override async Task CanDisposeAfterCancelingQueuedRequest() [Fact] public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -441,8 +626,15 @@ public override async Task CanCancelWaitAndAcquireAsyncBeforeQueuing() [Fact] public override async Task CancelUpdatesQueueLimit() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -464,8 +656,15 @@ public override async Task CancelUpdatesQueueLimit() [Fact] public override void NoMetadataOnAcquiredLease() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.False(lease.TryGetMetadata(MetadataName.RetryAfter, out _)); } @@ -473,8 +672,15 @@ public override void NoMetadataOnAcquiredLease() [Fact] public override void MetadataNamesContainsAllMetadata() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); using var lease = limiter.Acquire(1); Assert.Collection(lease.MetadataNames, metadataName => Assert.Equal(metadataName, MetadataName.RetryAfter.Name)); } @@ -482,8 +688,15 @@ public override void MetadataNamesContainsAllMetadata() [Fact] public override async Task DisposeReleasesQueuedAcquires() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -509,8 +722,15 @@ public override async Task DisposeReleasesQueuedAcquires() [Fact] public override async Task DisposeAsyncReleasesQueuedAcquires() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); var wait1 = limiter.WaitAndAcquireAsync(1); var wait2 = limiter.WaitAndAcquireAsync(1); @@ -536,8 +756,15 @@ public override async Task DisposeAsyncReleasesQueuedAcquires() [Fact] public async Task RetryMetadataOnFailedWaitAsync() { - var options = new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), 1, autoReplenishment: false); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(20), + TokensPerPeriod = 1, + AutoReplenishment = false + }; var limiter = new TokenBucketRateLimiter(options); using var lease = limiter.Acquire(2); @@ -556,8 +783,15 @@ public async Task RetryMetadataOnFailedWaitAsync() [Fact] public async Task CorrectRetryMetadataWithQueuedItem() { - var options = new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), 1, autoReplenishment: false); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(20), + TokensPerPeriod = 1, + AutoReplenishment = false + }; var limiter = new TokenBucketRateLimiter(options); using var lease = limiter.Acquire(2); @@ -574,8 +808,15 @@ public async Task CorrectRetryMetadataWithQueuedItem() [Fact] public async Task CorrectRetryMetadataWithMultipleTokensPerPeriod() { - var options = new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), 2, autoReplenishment: false); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(20), + TokensPerPeriod = 2, + AutoReplenishment = false + }; var limiter = new TokenBucketRateLimiter(options); using var lease = limiter.Acquire(2); @@ -592,8 +833,15 @@ public async Task CorrectRetryMetadataWithMultipleTokensPerPeriod() [Fact] public async Task CorrectRetryMetadataWithLargeTokensPerPeriod() { - var options = new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), 100, autoReplenishment: false); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(20), + TokensPerPeriod = 100, + AutoReplenishment = false + }; var limiter = new TokenBucketRateLimiter(options); using var lease = limiter.Acquire(2); @@ -610,8 +858,15 @@ public async Task CorrectRetryMetadataWithLargeTokensPerPeriod() [Fact] public async Task CorrectRetryMetadataWithNonZeroAvailableItems() { - var options = new TokenBucketRateLimiterOptions(3, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(20), 1, autoReplenishment: false); + var options = new TokenBucketRateLimiterOptions + { + TokenLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(20), + TokensPerPeriod = 1, + AutoReplenishment = false + }; var limiter = new TokenBucketRateLimiter(options); using var lease = limiter.Acquire(2); @@ -625,8 +880,15 @@ public async Task CorrectRetryMetadataWithNonZeroAvailableItems() [Fact] public void TryReplenishHonorsTokensPerPeriod() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(7, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 3, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 7, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 3, + AutoReplenishment = false + }); Assert.True(limiter.Acquire(5).IsAcquired); Assert.False(limiter.Acquire(3).IsAcquired); @@ -641,8 +903,15 @@ public void TryReplenishHonorsTokensPerPeriod() [Fact] public void TryReplenishWithAllTokensAvailable_Noops() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.Equal(2, limiter.GetAvailablePermits()); Assert.True(limiter.TryReplenish()); Assert.Equal(2, limiter.GetAvailablePermits()); @@ -651,8 +920,15 @@ public void TryReplenishWithAllTokensAvailable_Noops() [Fact] public void TryReplenishWithAutoReplenish_ReturnsFalse() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromSeconds(1), 1, autoReplenishment: true)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromSeconds(1), + TokensPerPeriod = 1, + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); Assert.False(limiter.TryReplenish()); Assert.Equal(2, limiter.GetAvailablePermits()); @@ -661,8 +937,15 @@ public void TryReplenishWithAutoReplenish_ReturnsFalse() [Fact] public async Task AutoReplenish_ReplenishesTokens() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 1, - TimeSpan.FromMilliseconds(1000), 1, autoReplenishment: true)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(1000), + TokensPerPeriod = 1, + AutoReplenishment = true + }); Assert.Equal(2, limiter.GetAvailablePermits()); limiter.Acquire(2); @@ -673,8 +956,15 @@ public async Task AutoReplenish_ReplenishesTokens() [Fact] public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfNewestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -696,8 +986,15 @@ public override async Task CanAcquireResourcesWithWaitAndAcquireAsyncWithQueuedI [Fact] public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueuedItemsIfOldestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -722,8 +1019,15 @@ public override async Task CannotAcquireResourcesWithWaitAndAcquireAsyncWithQueu [Fact] public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -744,8 +1048,15 @@ public override async Task CanAcquireResourcesWithAcquireWithQueuedItemsIfNewest [Fact] public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOldestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.OldestFirst, 3, - TimeSpan.Zero, 2, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 3, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 2, + AutoReplenishment = false + }); var lease = limiter.Acquire(1); Assert.True(lease.IsAcquired); @@ -767,8 +1078,15 @@ public override async Task CannotAcquireResourcesWithAcquireWithQueuedItemsIfOld [Fact] public async Task ReplenishWorksWithTicksOverInt32Max() { - using var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(10, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), 1, autoReplenishment: false)); + using var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 10, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(2), + TokensPerPeriod = 1, + AutoReplenishment = false + }); var lease = limiter.Acquire(10); Assert.True(lease.IsAcquired); @@ -800,8 +1118,15 @@ public async Task ReplenishWorksWithTicksOverInt32Max() [Fact] public override void NullIdleDurationWhenActive() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(2), + TokensPerPeriod = 1, + AutoReplenishment = false + }); limiter.Acquire(1); Assert.Null(limiter.IdleDuration); } @@ -809,8 +1134,15 @@ public override void NullIdleDurationWhenActive() [Fact] public override async Task IdleDurationUpdatesWhenIdle() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.FromMilliseconds(2), 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.FromMilliseconds(2), + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.NotNull(limiter.IdleDuration); var previousDuration = limiter.IdleDuration; await Task.Delay(15); @@ -820,8 +1152,15 @@ public override async Task IdleDurationUpdatesWhenIdle() [Fact] public override void IdleDurationUpdatesWhenChangingFromActive() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - TimeSpan.Zero, 1, autoReplenishment: false)); + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = TimeSpan.Zero, + TokensPerPeriod = 1, + AutoReplenishment = false + }); limiter.Acquire(1); limiter.TryReplenish(); Assert.NotNull(limiter.IdleDuration); @@ -831,14 +1170,28 @@ public override void IdleDurationUpdatesWhenChangingFromActive() public void ReplenishingRateLimiterPropertiesHaveCorrectValues() { var replenishPeriod = TimeSpan.FromMinutes(1); - using ReplenishingRateLimiter limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, 1, autoReplenishment: true)); + using ReplenishingRateLimiter limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = replenishPeriod, + TokensPerPeriod = 1, + AutoReplenishment = true + }); Assert.True(limiter.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter.ReplenishmentPeriod); replenishPeriod = TimeSpan.FromSeconds(2); - using ReplenishingRateLimiter limiter2 = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 2, - replenishPeriod, 1, autoReplenishment: false)); + using ReplenishingRateLimiter limiter2 = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 2, + ReplenishmentPeriod = replenishPeriod, + TokensPerPeriod = 1, + AutoReplenishment = false + }); Assert.False(limiter2.IsAutoReplenishing); Assert.Equal(replenishPeriod, limiter2.ReplenishmentPeriod); } From 1e732b5233a312d2c3ee283d040227293fab3900 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 16:22:20 -0700 Subject: [PATCH 29/60] Update ConcurrencyLimiter.cs --- .../System/Threading/RateLimiting/ConcurrencyLimiter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index b18b2a220d2974..6fc87c6f431f6d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -39,9 +39,13 @@ public sealed class ConcurrencyLimiter : RateLimiter public ConcurrencyLimiter(ConcurrencyLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.PermitLimit <= 0 || options.QueueLimit <= 0) + if (options.PermitLimit <= 0) { - throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.QueueLimit)} must be set to values greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to values greater than 0."); + } + if (options.QueueLimit < 0) + { + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); } _permitCount = _options.PermitLimit; } From 17df529d76b7aaf2a70f12f45cbdbc0e0f73267b Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 16:23:01 -0700 Subject: [PATCH 30/60] Update FixedWindowRateLimiter.cs --- .../Threading/RateLimiting/FixedWindowRateLimiter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index bd4cd891db2be1..2fa641876c0ea6 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -45,9 +45,13 @@ public sealed class FixedWindowRateLimiter : ReplenishingRateLimiter public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.Window.Equals(TimeSpan.Zero)) + if (options.PermitLimit <= 0 || options.Window.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, and {nameof(options.Window)} must all be set to values greater than 0."); + throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.Window)} must be set to values greater than 0."); + } + if (options.QueueLimit < 0) + { + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); } _requestCount = options.PermitLimit; From b422fe6c3507f6821449385129a4af739ee5cbea Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 16:23:35 -0700 Subject: [PATCH 31/60] Update SlidingWindowRateLimiter.cs --- .../Threading/RateLimiting/SlidingWindowRateLimiter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 82847a0231bdfc..cde0bf06a25f59 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -48,9 +48,13 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.PermitLimit <= 0 || options.QueueLimit <= 0 || options.SegmentsPerWindow <= 0 || options.Window.Equals(TimeSpan.Zero)) + if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0 || options.Window.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.QueueLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values greater than 0."); + } + if (options.QueueLimit < 0) + { + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); } _requestCount = options.PermitLimit; From 62e863c363f52e3d04a9fd7ee7bfc4d0d124ab4a Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 20 Jul 2022 16:23:58 -0700 Subject: [PATCH 32/60] Update TokenBucketRateLimiter.cs --- .../Threading/RateLimiting/TokenBucketRateLimiter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index a4624d9d81c71e..1c7bfe6d16c8d4 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -46,9 +46,13 @@ public sealed class TokenBucketRateLimiter : ReplenishingRateLimiter public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.TokenLimit <= 0 || options.QueueLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) + if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.QueueLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values greater than 0."); + throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values greater than 0."); + } + if (options.QueueLimit < 0) + { + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); } _tokenCount = options.TokenLimit; From ce015014a1a4df5a57d6a62ad5f938bfadb7831e Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:18:34 -0700 Subject: [PATCH 33/60] Update FixedWindowRateLimiter.cs --- .../System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 2fa641876c0ea6..35d80b22828430 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -45,9 +45,9 @@ public sealed class FixedWindowRateLimiter : ReplenishingRateLimiter public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.PermitLimit <= 0 || options.Window.Equals(TimeSpan.Zero)) + if (options.PermitLimit <= 0) { - throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.Window)} must be set to values greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); } if (options.QueueLimit < 0) { From 1b3d366881a8bba2616dcaefe78fffa17ef87336 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:19:16 -0700 Subject: [PATCH 34/60] Update SlidingWindowRateLimiter.cs --- .../System/Threading/RateLimiting/SlidingWindowRateLimiter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index cde0bf06a25f59..708e6a6f569a87 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -48,9 +48,9 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0 || options.Window.Equals(TimeSpan.Zero)) + if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0) { - throw new ArgumentException($"{nameof(options.PermitLimit)}, {nameof(options.SegmentsPerWindow)}, and {nameof(options.Window)} must all be set to values greater than 0."); + throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.SegmentsPerWindow)} must be set to values greater than 0."); } if (options.QueueLimit < 0) { From ae49b583f09a80d9345829935487c1425fe9f487 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:20:02 -0700 Subject: [PATCH 35/60] Update TokenBucketRateLimiter.cs --- .../src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 1c7bfe6d16c8d4..62a87095ac13fe 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -48,7 +48,7 @@ public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) { - throw new ArgumentException($"{nameof(options.TokenLimit)}, {nameof(options.TokensPerPeriod)}, and {nameof(options.ReplenishmentPeriod)} must all be set to values greater than 0."); + throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0."); } if (options.QueueLimit < 0) { From 954b9786d73ef08c5d2565d60c0dec8ed3eb652d Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:21:44 -0700 Subject: [PATCH 36/60] Update FixedWindowRateLimiterTests.cs --- .../tests/FixedWindowRateLimiterTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs index 400b47d9bd9c00..2dbf5aef041830 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs @@ -35,24 +35,24 @@ public override void CanAcquireResource() [Fact] public override void InvalidOptionsThrows() { - Assert.Throws( - () => new FixedWindowRateLimiterOptions + Assert.Throws( + () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions { PermitLimit = -1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = 1, Window = TimeSpan.FromMinutes(2), AutoReplenishment = false - }); - Assert.Throws( - () => new FixedWindowRateLimiterOptions + })); + Assert.Throws( + () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = -1, Window = TimeSpan.FromMinutes(2), AutoReplenishment = false - }); + })); } [Fact] From 629e3f63d164b8d009a2d95965e889535c8e6cc1 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:22:54 -0700 Subject: [PATCH 37/60] Update SlidingWindowRateLimiterTests.cs --- .../tests/SlidingWindowRateLimiterTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs index 71f66ea71bc573..62c0620076dfac 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs @@ -37,8 +37,8 @@ public override void CanAcquireResource() [Fact] public override void InvalidOptionsThrows() { - Assert.Throws( - () => new SlidingWindowRateLimiterOptions + Assert.Throws( + () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions { PermitLimit = -1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -46,9 +46,9 @@ public override void InvalidOptionsThrows() Window = TimeSpan.FromMinutes(2), SegmentsPerWindow = 1, AutoReplenishment = false - }); - Assert.Throws( - () => new SlidingWindowRateLimiterOptions + })); + Assert.Throws( + () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -56,9 +56,9 @@ public override void InvalidOptionsThrows() Window = TimeSpan.FromMinutes(2), SegmentsPerWindow = 1, AutoReplenishment = false - }); - Assert.Throws( - () => new SlidingWindowRateLimiterOptions + })); + Assert.Throws( + () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -66,7 +66,7 @@ public override void InvalidOptionsThrows() Window = TimeSpan.FromMinutes(2), SegmentsPerWindow = -1, AutoReplenishment = false - }); + })); } [Fact] From 111420f7b113b85ca3bf4727989457305c092dfa Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 08:23:48 -0700 Subject: [PATCH 38/60] Update TokenBucketRateLimiterTests.cs --- .../tests/TokenBucketRateLimiterTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs index e125a0c2a5327e..5d3fa50d69130d 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs @@ -36,8 +36,8 @@ public override void CanAcquireResource() [Fact] public override void InvalidOptionsThrows() { - Assert.Throws( - () => new TokenBucketRateLimiterOptions + Assert.Throws( + () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions { TokenLimit = -1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -45,9 +45,9 @@ public override void InvalidOptionsThrows() ReplenishmentPeriod = TimeSpan.FromMinutes(2), TokensPerPeriod = 1, AutoReplenishment = false - }); - Assert.Throws( - () => new TokenBucketRateLimiterOptions + })); + Assert.Throws( + () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions { TokenLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -55,9 +55,9 @@ public override void InvalidOptionsThrows() ReplenishmentPeriod = TimeSpan.FromMinutes(2), TokensPerPeriod = 1, AutoReplenishment = false - }); - Assert.Throws( - () => new TokenBucketRateLimiterOptions + })); + Assert.Throws( + () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions { TokenLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, @@ -65,7 +65,7 @@ public override void InvalidOptionsThrows() ReplenishmentPeriod = TimeSpan.FromMinutes(2), TokensPerPeriod = -1, AutoReplenishment = false - }); + })); } [Fact] From efd9d41d3d3e21255f57c42f317527180caf5b0e Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 09:17:43 -0700 Subject: [PATCH 39/60] Update TokenBucketRateLimiter.cs --- .../System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 62a87095ac13fe..6aa2f3aa4b64b0 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -46,13 +46,13 @@ public sealed class TokenBucketRateLimiter : ReplenishingRateLimiter public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); - if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0 || options.ReplenishmentPeriod.Equals(TimeSpan.Zero)) + if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0) { throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0."); } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } _tokenCount = options.TokenLimit; From bec4227faf121a30be4338b80673a44b363b1e3f Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 09:18:05 -0700 Subject: [PATCH 40/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs Co-authored-by: Brennan --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 6fc87c6f431f6d..28507e61c03cf6 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -45,7 +45,7 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } _permitCount = _options.PermitLimit; } From 08fa3be07e2d703e58224c86902d9171f274b1d6 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 09:18:15 -0700 Subject: [PATCH 41/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs Co-authored-by: Brennan --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 28507e61c03cf6..50a1dfb90399f8 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -41,7 +41,7 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) _options = options ?? throw new ArgumentNullException(nameof(options)); if (options.PermitLimit <= 0) { - throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to values greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); } if (options.QueueLimit < 0) { From 87ed11176b6e580c7745b190c211d708936ee9a7 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 09:19:01 -0700 Subject: [PATCH 42/60] Update FixedWindowRateLimiter.cs --- .../src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 35d80b22828430..903dbe04281b08 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -51,7 +51,7 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } _requestCount = options.PermitLimit; From 82e405713d9bded4174ef3e099cb1edbd8fdcba7 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Thu, 21 Jul 2022 09:19:30 -0700 Subject: [PATCH 43/60] Update SlidingWindowRateLimiter.cs --- .../System/Threading/RateLimiting/SlidingWindowRateLimiter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 708e6a6f569a87..15900bdb2ccc7c 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -54,7 +54,7 @@ public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to values greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } _requestCount = options.PermitLimit; From 7feff7e4fc0b228e4acbdb86b90bcab1e80ad8d0 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 09:28:56 -0700 Subject: [PATCH 44/60] Fixup --- .../Threading/RateLimiting/ConcurrencyLimiter.cs | 10 +++++++++- .../RateLimiting/FixedWindowRateLimiter.cs | 12 +++++++++++- .../RateLimiting/FixedWindowRateLimiterOptions.cs | 2 +- .../RateLimiting/SlidingWindowRateLimiter.cs | 13 ++++++++++++- .../RateLimiting/SlidingWindowRateLimiterOptions.cs | 2 +- .../RateLimiting/TokenBucketRateLimiter.cs | 13 ++++++++++++- .../RateLimiting/TokenBucketRateLimiterOptions.cs | 2 +- 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 50a1dfb90399f8..2195e5882937c0 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -38,7 +38,7 @@ public sealed class ConcurrencyLimiter : RateLimiter /// Options to specify the behavior of the . public ConcurrencyLimiter(ConcurrencyLimiterOptions options) { - _options = options ?? throw new ArgumentNullException(nameof(options)); + ArgumentNullException.ThrowIfNull(options); if (options.PermitLimit <= 0) { throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); @@ -47,6 +47,14 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } + + _options = new ConcurrencyLimiterOptions + { + PermitLimit = options.PermitLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit + }; + _permitCount = _options.PermitLimit; } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 903dbe04281b08..aa94fa7f4c92c7 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -44,7 +44,7 @@ public sealed class FixedWindowRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { - _options = options ?? throw new ArgumentNullException(nameof(options)); + ArgumentNullException.ThrowIfNull(options); if (options.PermitLimit <= 0) { throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); @@ -53,6 +53,16 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } + + _options = new FixedWindowRateLimiterOptions + { + PermitLimit = options.PermitLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + Window = options.Window, + AutoReplenishment = options.AutoReplenishment + }; + _requestCount = options.PermitLimit; _idleSince = _lastReplenishmentTick = Stopwatch.GetTimestamp(); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index c8aca6226fbd7f..e613928ed1105b 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -19,7 +19,7 @@ public sealed class FixedWindowRateLimiterOptions /// will be calling to refresh counters. /// /// - /// 'true' by default. + /// by default. /// public bool AutoReplenishment { get; set; } = true; diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 15900bdb2ccc7c..204059fd89c579 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -47,7 +47,7 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { - _options = options ?? throw new ArgumentNullException(nameof(options)); + ArgumentNullException.ThrowIfNull(options); if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0) { throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.SegmentsPerWindow)} must be set to values greater than 0."); @@ -56,6 +56,17 @@ public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } + + _options = new SlidingWindowRateLimiterOptions + { + PermitLimit = options.PermitLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + Window = options.Window, + SegmentsPerWindow = options.SegmentsPerWindow, + AutoReplenishment = options.AutoReplenishment + }; + _requestCount = options.PermitLimit; // _requestsPerSegment holds the no. of acquired requests in each window segment diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index 1f3fc8b2b4a8f9..cf17d0e3c24527 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -25,7 +25,7 @@ public sealed class SlidingWindowRateLimiterOptions /// will be calling to replenish tokens. /// /// - /// 'true' by default. + /// by default. /// public bool AutoReplenishment { get; set; } = true; diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 6aa2f3aa4b64b0..7ead82d080f736 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -45,7 +45,7 @@ public sealed class TokenBucketRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { - _options = options ?? throw new ArgumentNullException(nameof(options)); + ArgumentNullException.ThrowIfNull(options); if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0) { throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0."); @@ -54,6 +54,17 @@ public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } + + _options = new TokenBucketRateLimiterOptions + { + TokenLimit = options.TokenLimit, + QueueProcessingOrder = options.QueueProcessingOrder, + QueueLimit = options.QueueLimit, + ReplenishmentPeriod = options.ReplenishmentPeriod, + TokensPerPeriod = options.TokensPerPeriod, + AutoReplenishment = options.AutoReplenishment + }; + _tokenCount = options.TokenLimit; _idleSince = _lastReplenishmentTick = Stopwatch.GetTimestamp(); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index 894f77c1b7676f..f24d21fb3711e7 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -25,7 +25,7 @@ public sealed class TokenBucketRateLimiterOptions /// will be calling to replenish tokens. /// /// - /// 'true' by default. + /// by default. /// public bool AutoReplenishment { get; set; } = true; From c7acb7b2f92fa871f8a299aad7f50bec35d82f3a Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 09:57:49 -0700 Subject: [PATCH 45/60] Whitespace --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 2 +- .../src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 2195e5882937c0..b63bc871213d1d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -54,7 +54,7 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) QueueProcessingOrder = options.QueueProcessingOrder, QueueLimit = options.QueueLimit }; - + _permitCount = _options.PermitLimit; } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index aa94fa7f4c92c7..6af8fb9cc7af92 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -53,7 +53,7 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); } - + _options = new FixedWindowRateLimiterOptions { PermitLimit = options.PermitLimit, From f1345c4808f7d89d5b2221c6b400787e22a316a6 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 10:31:04 -0700 Subject: [PATCH 46/60] ArgumentNullException --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 5 ++++- .../System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 5 ++++- .../Threading/RateLimiting/SlidingWindowRateLimiter.cs | 5 ++++- .../System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index b63bc871213d1d..94fd9feb2b3110 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -38,7 +38,10 @@ public sealed class ConcurrencyLimiter : RateLimiter /// Options to specify the behavior of the . public ConcurrencyLimiter(ConcurrencyLimiterOptions options) { - ArgumentNullException.ThrowIfNull(options); + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } if (options.PermitLimit <= 0) { throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 6af8fb9cc7af92..0d6fc92546ec33 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -44,7 +44,10 @@ public sealed class FixedWindowRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { - ArgumentNullException.ThrowIfNull(options); + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } if (options.PermitLimit <= 0) { throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 204059fd89c579..26c598b10525e4 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -47,7 +47,10 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { - ArgumentNullException.ThrowIfNull(options); + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0) { throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.SegmentsPerWindow)} must be set to values greater than 0."); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 7ead82d080f736..795963929013dc 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -45,7 +45,10 @@ public sealed class TokenBucketRateLimiter : ReplenishingRateLimiter /// Options to specify the behavior of the . public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { - ArgumentNullException.ThrowIfNull(options); + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0) { throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0."); From 0e89029a6905d317b6d522016fbde05185730ad2 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 11:16:03 -0700 Subject: [PATCH 47/60] React to test change --- .../tests/PartitionedRateLimiterTests.cs | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs index 39b85f628684fc..4c97b03c65d59a 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs @@ -648,12 +648,22 @@ public void Translate_AcquirePassesThroughToInnerLimiter() if (resource == "1") { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } else { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } }); @@ -687,12 +697,22 @@ public async Task Translate_WaitAsyncPassesThroughToInnerLimiter() if (resource == "1") { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } else { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } }); @@ -726,12 +746,22 @@ public void Translate_GetAvailablePermitsPassesThroughToInnerLimiter() if (resource == "1") { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } else { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } }); @@ -774,12 +804,22 @@ public void Translate_DisposeDoesNotDisposeInnerLimiter() if (resource == "1") { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } else { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } }); @@ -806,12 +846,22 @@ public async Task Translate_DisposeAsyncDoesNotDisposeInnerLimiter() if (resource == "1") { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } else { return RateLimitPartition.GetConcurrencyLimiter(1, - _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + _ => new ConcurrencyLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1 + }); } }); From 9d6b38bb604923672a0f7f92c143b2dddeaf89fb Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 12:29:22 -0700 Subject: [PATCH 48/60] Fix tests --- .../tests/ConcurrencyLimiterTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs index aa38aa2d53a1e4..bac33bae26ef52 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs @@ -11,18 +11,18 @@ public class ConcurrencyLimiterTests : BaseRateLimiterTests [Fact] public override void InvalidOptionsThrows() { - Assert.Throws(() => new ConcurrencyLimiterOptions + Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions { PermitLimit = -1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = 1 - }); - Assert.Throws(() => new ConcurrencyLimiterOptions + })); + Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = -1 - }); + })); } [Fact] @@ -393,7 +393,7 @@ public override async Task CanDequeueMultipleResourcesAtOnce() { PermitLimit = 2, QueueProcessingOrder = QueueProcessingOrder.OldestFirst, - QueueLimit = 1 + QueueLimit = 2 }); using var lease = await limiter.WaitAndAcquireAsync(2); Assert.True(lease.IsAcquired); From d1481528d96de29228c67dfc6004a5ce0a852b9b Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 21 Jul 2022 13:50:23 -0700 Subject: [PATCH 49/60] Another test fix --- .../tests/ConcurrencyLimiterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs index bac33bae26ef52..ec6fac77c57304 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs @@ -11,13 +11,13 @@ public class ConcurrencyLimiterTests : BaseRateLimiterTests [Fact] public override void InvalidOptionsThrows() { - Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions + Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions { PermitLimit = -1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, QueueLimit = 1 })); - Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions + Assert.Throws(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.NewestFirst, From 8e06f6a8ad88a10722b37c17269c114bdc0c636f Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Fri, 22 Jul 2022 09:39:47 -0700 Subject: [PATCH 50/60] Feedback --- .../src/System/Threading/RateLimiting/ConcurrencyLimiter.cs | 4 ++-- .../System/Threading/RateLimiting/FixedWindowRateLimiter.cs | 4 ++-- .../System/Threading/RateLimiting/SlidingWindowRateLimiter.cs | 4 ++-- .../System/Threading/RateLimiting/TokenBucketRateLimiter.cs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 94fd9feb2b3110..0c4b8b7e1b328d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -44,11 +44,11 @@ public ConcurrencyLimiter(ConcurrencyLimiterOptions options) } if (options.PermitLimit <= 0) { - throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0.", nameof(options)); } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } _options = new ConcurrencyLimiterOptions diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 0d6fc92546ec33..65a9336c8c3d4c 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -50,11 +50,11 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) } if (options.PermitLimit <= 0) { - throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0."); + throw new ArgumentException($"{nameof(options.PermitLimit)} must be set to a value greater than 0.", nameof(options)); } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } _options = new FixedWindowRateLimiterOptions diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 26c598b10525e4..8cd5e4ea63e100 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -53,11 +53,11 @@ public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) } if (options.PermitLimit <= 0 || options.SegmentsPerWindow <= 0) { - throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.SegmentsPerWindow)} must be set to values greater than 0."); + throw new ArgumentException($"Both {nameof(options.PermitLimit)} and {nameof(options.SegmentsPerWindow)} must be set to values greater than 0.", nameof(options)); } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } _options = new SlidingWindowRateLimiterOptions diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 795963929013dc..62a59c1576d52d 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -51,11 +51,11 @@ public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) } if (options.TokenLimit <= 0 || options.TokensPerPeriod <= 0) { - throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0."); + throw new ArgumentException($"Both {nameof(options.TokenLimit)} and {nameof(options.TokensPerPeriod)} must be set to values greater than 0.", nameof(options)); } if (options.QueueLimit < 0) { - throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0."); + throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } _options = new TokenBucketRateLimiterOptions From dd9eca1f920a3f357c07139178e13e39509a7ed8 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:54:45 -0700 Subject: [PATCH 51/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs Co-authored-by: Brennan --- .../System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs index e69f4cb11bddb0..23514c5906c117 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs @@ -24,7 +24,7 @@ public sealed class ConcurrencyLimiterOptions /// /// Maximum number of permits that can be queued concurrently. - /// Must be set to a value > 0 by the time these options are passed to the constructor of . + /// Must be set to a value >= 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From 8b11ec5a8378dc7dd38e6b9a213da1634629ae19 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:54:53 -0700 Subject: [PATCH 52/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index e613928ed1105b..a4607c520e2822 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -39,7 +39,7 @@ public sealed class FixedWindowRateLimiterOptions /// /// Maximum cumulative permit count of queued acquisition requests. - /// Must be set to a value > 0 by the time these options are passed to the constructor of . + /// Must be set to a value >= 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From 3007da643d1dacc77c4d7f5da9bcc9c7b399c27a Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:55:01 -0700 Subject: [PATCH 53/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/FixedWindowRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs index a4607c520e2822..8395b19d62d5d1 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class FixedWindowRateLimiterOptions { /// /// Specifies the time window that takes in the requests. - /// Must be set to a nonzero value by the time these options are passed to the constructor of . + /// Must be set to a value >= by the time these options are passed to the constructor of . /// public TimeSpan Window { get; set; } = TimeSpan.Zero; From 1857521d17b0ede0dbe670927ca32a742fb48207 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:55:17 -0700 Subject: [PATCH 54/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index cf17d0e3c24527..e3e9ea8323ad70 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class SlidingWindowRateLimiterOptions { /// /// Specifies the minimum period between replenishments. - /// Must be set to a nonzero value by the time these options are passed to the constructor of . + /// Must be set to a value >= by the time these options are passed to the constructor of . /// public TimeSpan Window { get; set; } = TimeSpan.Zero; From 02831bda36fa5f3d108dbaad20a7977962fd7db8 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:55:26 -0700 Subject: [PATCH 55/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs index e3e9ea8323ad70..8d000e7656c4c7 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs @@ -45,7 +45,7 @@ public sealed class SlidingWindowRateLimiterOptions /// /// Maximum cumulative permit count of queued acquisition requests. - /// Must be set to a value > 0 by the time these options are passed to the constructor of . + /// Must be set to a value >= 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From 7966a362a4226ded2b6af97fcd528fa6202ab373 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:56:03 -0700 Subject: [PATCH 56/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/TokenBucketRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index f24d21fb3711e7..9b0984ba752841 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -10,7 +10,7 @@ public sealed class TokenBucketRateLimiterOptions { /// /// Specifies the minimum period between replenishments. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a value >= by the time these options are passed to the constructor of . /// public TimeSpan ReplenishmentPeriod { get; set; } = TimeSpan.Zero; From 2c90029978357770c53202cf4f7453775cc2e116 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:56:15 -0700 Subject: [PATCH 57/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/TokenBucketRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index 9b0984ba752841..8c501e8c006aa8 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -31,7 +31,7 @@ public sealed class TokenBucketRateLimiterOptions /// /// Maximum number of tokens that can be in the bucket at any time. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int TokenLimit { get; set; } From 855fe118e640cfecf74c45f026591ad22d76fec3 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:56:22 -0700 Subject: [PATCH 58/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/TokenBucketRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index 8c501e8c006aa8..c17aefe5574066 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -16,7 +16,7 @@ public sealed class TokenBucketRateLimiterOptions /// /// Specifies the maximum number of tokens to restore each replenishment. - /// Must be set to a value >= 0 by the team these options are passed to the constructor of . + /// Must be set to a value > 0 by the time these options are passed to the constructor of . /// public int TokensPerPeriod { get; set; } From c31d883ecf523c5832d4be8b9bc8296eb2d1dcfe Mon Sep 17 00:00:00 2001 From: William Godbe Date: Fri, 22 Jul 2022 14:56:28 -0700 Subject: [PATCH 59/60] Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs Co-authored-by: Brennan --- .../Threading/RateLimiting/TokenBucketRateLimiterOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs index c17aefe5574066..c3f29c169de69a 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs @@ -45,7 +45,7 @@ public sealed class TokenBucketRateLimiterOptions /// /// Maximum cumulative token count of queued acquisition requests. - /// Must be set to a nonzero value by the team these options are passed to the constructor of . + /// Must be set to a value >= 0 by the time these options are passed to the constructor of . /// public int QueueLimit { get; set; } } From 8fb231d71354933ca054a104e49a20eea81e1b07 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Fri, 22 Jul 2022 15:01:38 -0700 Subject: [PATCH 60/60] Fix checks, add test --- .../Threading/RateLimiting/FixedWindowRateLimiter.cs | 4 ++++ .../Threading/RateLimiting/SlidingWindowRateLimiter.cs | 4 ++++ .../Threading/RateLimiting/TokenBucketRateLimiter.cs | 4 ++++ .../tests/FixedWindowRateLimiterTests.cs | 9 +++++++++ .../tests/SlidingWindowRateLimiterTests.cs | 10 ++++++++++ .../tests/TokenBucketRateLimiterTests.cs | 10 ++++++++++ 6 files changed, 41 insertions(+) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index 65a9336c8c3d4c..4538afa013c3e1 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -56,6 +56,10 @@ public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } + if (options.Window < TimeSpan.Zero) + { + throw new ArgumentException($"{nameof(options.Window)} must be set to a value greater than or equal to TimeSpan.Zero.", nameof(options)); + } _options = new FixedWindowRateLimiterOptions { diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 8cd5e4ea63e100..1694ccf4b7b9ba 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -59,6 +59,10 @@ public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } + if (options.Window < TimeSpan.Zero) + { + throw new ArgumentException($"{nameof(options.Window)} must be set to a value greater than or equal to TimeSpan.Zero.", nameof(options)); + } _options = new SlidingWindowRateLimiterOptions { diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 62a59c1576d52d..257422fdc6d90a 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -57,6 +57,10 @@ public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options) { throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options)); } + if (options.ReplenishmentPeriod < TimeSpan.Zero) + { + throw new ArgumentException($"{nameof(options.ReplenishmentPeriod)} must be set to a value greater than or equal to TimeSpan.Zero.", nameof(options)); + } _options = new TokenBucketRateLimiterOptions { diff --git a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs index 2dbf5aef041830..0f4b6bf9e7b16e 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs @@ -53,6 +53,15 @@ public override void InvalidOptionsThrows() Window = TimeSpan.FromMinutes(2), AutoReplenishment = false })); + Assert.Throws( + () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.MinValue, + AutoReplenishment = false + })); } [Fact] diff --git a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs index 62c0620076dfac..a582cc07d4d053 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs @@ -67,6 +67,16 @@ public override void InvalidOptionsThrows() SegmentsPerWindow = -1, AutoReplenishment = false })); + Assert.Throws( + () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + Window = TimeSpan.MinValue, + SegmentsPerWindow = 1, + AutoReplenishment = false + })); } [Fact] diff --git a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs index 5d3fa50d69130d..9bfeac0ab2e9eb 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs @@ -66,6 +66,16 @@ public override void InvalidOptionsThrows() TokensPerPeriod = -1, AutoReplenishment = false })); + Assert.Throws( + () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.NewestFirst, + QueueLimit = 1, + ReplenishmentPeriod = TimeSpan.MinValue, + TokensPerPeriod = 1, + AutoReplenishment = false + })); } [Fact]