Make RateLimiterOptions follow Options pattern (#72530)
authorWilliam Godbe <wigodbe@microsoft.com>
Tue, 26 Jul 2022 16:28:13 +0000 (09:28 -0700)
committerGitHub <noreply@github.com>
Tue, 26 Jul 2022 16:28:13 +0000 (09:28 -0700)
* Update ConcurrencyLimiterOptions.cs

* Update FixedWindowRateLimiterOptions.cs

* Update FixedWindowRateLimiterOptions.cs

* Update FixedWindowRateLimiterOptions.cs

* Update SlidingWindowRateLimiterOptions.cs

* Update TokenBucketRateLimiterOptions.cs

* Update ConcurrencyLimiter.cs

* Update FixedWindowRateLimiter.cs

* Update SlidingWindowRateLimiter.cs

* Update TokenBucketRateLimiter.cs

* Update ChainedLimiterTests.cs

* Update ConcurrencyLimiterOptions.cs

* Update FixedWindowRateLimiterOptions.cs

* Update SlidingWindowRateLimiterOptions.cs

* Update TokenBucketRateLimiterOptions.cs

* Update RateLimitPartition.cs

* Update System.Threading.RateLimiting.cs

* Update ChainedLimiterTests.cs

* Update ConcurrencyLimiter.cs

* Update FixedWindowRateLimiter.cs

* Update SlidingWindowRateLimiter.cs

* Update TokenBucketRateLimiter.cs

* Update ConcurrencyLimiterOptions.cs

* Update FixedWindowRateLimiterOptions.cs

* Update SlidingWindowRateLimiterOptions.cs

* Update ChainedLimiterTests.cs

* Update ChainedLimiterTests.cs

* Fix tests

* Update ConcurrencyLimiter.cs

* Update FixedWindowRateLimiter.cs

* Update SlidingWindowRateLimiter.cs

* Update TokenBucketRateLimiter.cs

* Update FixedWindowRateLimiter.cs

* Update SlidingWindowRateLimiter.cs

* Update TokenBucketRateLimiter.cs

* Update FixedWindowRateLimiterTests.cs

* Update SlidingWindowRateLimiterTests.cs

* Update TokenBucketRateLimiterTests.cs

* Update TokenBucketRateLimiter.cs

* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update FixedWindowRateLimiter.cs

* Update SlidingWindowRateLimiter.cs

* Fixup

* Whitespace

* ArgumentNullException

* React to test change

* Fix tests

* Another test fix

* Feedback

* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Update src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs

Co-authored-by: Brennan <brecon@microsoft.com>
* Fix checks, add test

Co-authored-by: Brennan <brecon@microsoft.com>
17 files changed:
src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiterOptions.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiterOptions.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitPartition.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiterOptions.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs
src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs
src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs
src/libraries/System.Threading.RateLimiting/tests/FixedWindowRateLimiterTests.cs
src/libraries/System.Threading.RateLimiting/tests/PartitionedRateLimiterTests.cs
src/libraries/System.Threading.RateLimiting/tests/RateLimiterPartitionTests.cs
src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs
src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs

index c53f41f..4c1f428 100644 (file)
@@ -18,10 +18,10 @@ namespace System.Threading.RateLimiting
     }
     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 @@ namespace System.Threading.RateLimiting
     }
     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
     {
@@ -151,13 +151,13 @@ namespace System.Threading.RateLimiting
     }
     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
     {
@@ -174,12 +174,12 @@ namespace System.Threading.RateLimiting
     }
     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; } }
     }
 }
index 2b38d6d..0c4b8b7 100644 (file)
@@ -38,7 +38,26 @@ namespace System.Threading.RateLimiting
         /// <param name="options">Options to specify the behavior of the <see cref="ConcurrencyLimiter"/>.</param>
         public ConcurrencyLimiter(ConcurrencyLimiterOptions options)
         {
-            _options = options ?? throw new ArgumentNullException(nameof(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.", nameof(options));
+            }
+            if (options.QueueLimit < 0)
+            {
+                throw new ArgumentException($"{nameof(options.QueueLimit)} must be set to a value greater than or equal to 0.", nameof(options));
+            }
+
+            _options = new ConcurrencyLimiterOptions
+            {
+                PermitLimit = options.PermitLimit,
+                QueueProcessingOrder = options.QueueProcessingOrder,
+                QueueLimit = options.QueueLimit
+            };
+
             _permitCount = _options.PermitLimit;
         }
 
index 104de7c..23514c5 100644 (file)
@@ -9,31 +9,10 @@ namespace System.Threading.RateLimiting
     public sealed class ConcurrencyLimiterOptions
     {
         /// <summary>
-        /// Initializes the <see cref="ConcurrencyLimiterOptions"/>.
-        /// </summary>
-        /// <param name="permitLimit">Maximum number of permits that can be leased concurrently.</param>
-        /// <param name="queueProcessingOrder">Determines the behaviour of <see cref="RateLimiter.WaitAndAcquireAsync"/> when not enough resources can be leased.</param>
-        /// <param name="queueLimit">Maximum number of permits that can be queued concurrently.</param>
-        /// <exception cref="ArgumentOutOfRangeException">When <paramref name="permitLimit"/> or <paramref name="queueLimit"/> are less than 0.</exception>
-        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;
-        }
-
-        /// <summary>
         /// Maximum number of permits that can be leased concurrently.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="ConcurrencyLimiter"/>.
         /// </summary>
-        public int PermitLimit { get; }
+        public int PermitLimit { get; set; }
 
         /// <summary>
         /// Determines the behaviour of <see cref="RateLimiter.WaitAndAcquireAsync"/> when not enough resources can be leased.
@@ -41,11 +20,12 @@ namespace System.Threading.RateLimiting
         /// <value>
         /// <see cref="QueueProcessingOrder.OldestFirst"/> by default.
         /// </value>
-        public QueueProcessingOrder QueueProcessingOrder { get; } = QueueProcessingOrder.OldestFirst;
+        public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst;
 
         /// <summary>
         /// 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 <see cref="ConcurrencyLimiter"/>.
         /// </summary>
-        public int QueueLimit { get; }
+        public int QueueLimit { get; set; }
     }
 }
index c6b1b67..4538afa 100644 (file)
@@ -44,7 +44,32 @@ namespace System.Threading.RateLimiting
         /// <param name="options">Options to specify the behavior of the <see cref="FixedWindowRateLimiter"/>.</param>
         public FixedWindowRateLimiter(FixedWindowRateLimiterOptions options)
         {
-            _options = options ?? throw new ArgumentNullException(nameof(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.", nameof(options));
+            }
+            if (options.QueueLimit < 0)
+            {
+                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
+            {
+                PermitLimit = options.PermitLimit,
+                QueueProcessingOrder = options.QueueProcessingOrder,
+                QueueLimit = options.QueueLimit,
+                Window = options.Window,
+                AutoReplenishment = options.AutoReplenishment
+            };
+
             _requestCount = options.PermitLimit;
 
             _idleSince = _lastReplenishmentTick = Stopwatch.GetTimestamp();
index a1a88de..8395b19 100644 (file)
@@ -9,56 +9,25 @@ namespace System.Threading.RateLimiting
     public sealed class FixedWindowRateLimiterOptions
     {
         /// <summary>
-        /// Initializes the <see cref="FixedWindowRateLimiterOptions"/>.
-        /// </summary>
-        /// <param name="permitLimit">Maximum number of requests that can be served in the window.</param>
-        /// <param name="queueProcessingOrder"></param>
-        /// <param name="queueLimit">Maximum number of unprocessed request counters waiting via <see cref="RateLimiter.WaitAndAcquireAsync(int, CancellationToken)"/>.</param>
-        /// <param name="window">
-        /// Specifies how often request counters can be replenished. Replenishing is triggered either by an internal timer if <paramref name="autoReplenishment"/> is true, or by calling <see cref="FixedWindowRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <param name="autoReplenishment">
-        /// Specifies whether request replenishment will be handled by the <see cref="FixedWindowRateLimiter"/> or by another party via <see cref="FixedWindowRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <exception cref="ArgumentOutOfRangeException">When <paramref name="permitLimit"/> or <paramref name="queueLimit"/> are less than 0. </exception>
-        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;
-        }
-
-        /// <summary>
         /// Specifies the time window that takes in the requests.
+        /// Must be set to a value >= <see cref="TimeSpan.Zero" /> by the time these options are passed to the constructor of <see cref="FixedWindowRateLimiter"/>.
         /// </summary>
-        public TimeSpan Window { get; }
+        public TimeSpan Window { get; set; } = TimeSpan.Zero;
 
         /// <summary>
         /// Specified whether the <see cref="FixedWindowRateLimiter"/> is automatically refresh counters or if someone else
         /// will be calling <see cref="FixedWindowRateLimiter.TryReplenish"/> to refresh counters.
         /// </summary>
-        public bool AutoReplenishment { get; }
+        /// <value>
+        /// <see langword="true" /> by default.
+        /// </value>
+        public bool AutoReplenishment { get; set; } = true;
 
         /// <summary>
         /// Maximum number of permit counters that can be allowed in a window.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="FixedWindowRateLimiter"/>.
         /// </summary>
-        public int PermitLimit { get; }
+        public int PermitLimit { get; set; }
 
         /// <summary>
         /// Determines the behaviour of <see cref="RateLimiter.WaitAndAcquireAsync"/> when not enough resources can be leased.
@@ -66,11 +35,12 @@ namespace System.Threading.RateLimiting
         /// <value>
         /// <see cref="QueueProcessingOrder.OldestFirst"/> by default.
         /// </value>
-        public QueueProcessingOrder QueueProcessingOrder { get; }
+        public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst;
 
         /// <summary>
         /// 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 <see cref="FixedWindowRateLimiter"/>.
         /// </summary>
-        public int QueueLimit { get; }
+        public int QueueLimit { get; set; }
     }
 }
index 4042cce..f6b3e1a 100644 (file)
@@ -71,8 +71,15 @@ namespace System.Threading.RateLimiting
                 // 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 @@ namespace System.Threading.RateLimiting
                 // 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 @@ namespace System.Threading.RateLimiting
                 // 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);
             });
index 5911ef4..1694ccf 100644 (file)
@@ -47,7 +47,33 @@ namespace System.Threading.RateLimiting
         /// <param name="options">Options to specify the behavior of the <see cref="SlidingWindowRateLimiter"/>.</param>
         public SlidingWindowRateLimiter(SlidingWindowRateLimiterOptions options)
         {
-            _options = options ?? throw new ArgumentNullException(nameof(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.", nameof(options));
+            }
+            if (options.QueueLimit < 0)
+            {
+                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
+            {
+                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
index 075f247..8d000e7 100644 (file)
@@ -9,68 +9,31 @@ namespace System.Threading.RateLimiting
     public sealed class SlidingWindowRateLimiterOptions
     {
         /// <summary>
-        /// Initializes the <see cref="SlidingWindowRateLimiterOptions"/>.
-        /// </summary>
-        /// <param name="permitLimit">Maximum number of request counters that can be served in a window.</param>
-        /// <param name="queueProcessingOrder"></param>
-        /// <param name="queueLimit">Maximum number of unprocessed request counters waiting via <see cref="RateLimiter.WaitAndAcquireAsync(int, CancellationToken)"/>.</param>
-        /// <param name="window">
-        /// Specifies how often requests can be replenished. Replenishing is triggered either by an internal timer if <paramref name="autoReplenishment"/> is true, or by calling <see cref="SlidingWindowRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <param name="segmentsPerWindow">Specified how many segments a window can be divided into. The total requests a segment can serve cannot exceed the max limit.<paramref name="permitLimit"/>.</param>
-        /// <param name="autoReplenishment">
-        /// Specifies whether request replenishment will be handled by the <see cref="SlidingWindowRateLimiter"/> or by another party via <see cref="SlidingWindowRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <exception cref="ArgumentOutOfRangeException">When <paramref name="permitLimit"/>, <paramref name="queueLimit"/>, or <paramref name="segmentsPerWindow"/> are less than 0. </exception>
-        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;
-        }
-
-        /// <summary>
         /// Specifies the minimum period between replenishments.
+        /// Must be set to a value >= <see cref="TimeSpan.Zero" /> by the time these options are passed to the constructor of <see cref="SlidingWindowRateLimiter"/>.
         /// </summary>
-        public TimeSpan Window { get; }
+        public TimeSpan Window { get; set; } = TimeSpan.Zero;
 
         /// <summary>
         /// Specifies the maximum number of segments a window is divided into.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="SlidingWindowRateLimiter"/>.
         /// </summary>
-        public int SegmentsPerWindow { get; }
+        public int SegmentsPerWindow { get; set; }
 
         /// <summary>
         /// Specified whether the <see cref="SlidingWindowRateLimiter"/> is automatically replenishing request counters or if someone else
         /// will be calling <see cref="SlidingWindowRateLimiter.TryReplenish"/> to replenish tokens.
         /// </summary>
-        public bool AutoReplenishment { get; }
+        /// <value>
+        /// <see langword="true" /> by default.
+        /// </value>
+        public bool AutoReplenishment { get; set; } = true;
 
         /// <summary>
         /// Maximum number of requests that can be served in a window.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="SlidingWindowRateLimiter"/>.
         /// </summary>
-        public int PermitLimit { get; }
+        public int PermitLimit { get; set; }
 
         /// <summary>
         /// Determines the behaviour of <see cref="RateLimiter.WaitAndAcquireAsync"/> when not enough resources can be leased.
@@ -78,11 +41,12 @@ namespace System.Threading.RateLimiting
         /// <value>
         /// <see cref="QueueProcessingOrder.OldestFirst"/> by default.
         /// </value>
-        public QueueProcessingOrder QueueProcessingOrder { get; }
+        public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst;
 
         /// <summary>
         /// 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 <see cref="SlidingWindowRateLimiter"/>.
         /// </summary>
-        public int QueueLimit { get; }
+        public int QueueLimit { get; set; }
     }
 }
index d971fc3..257422f 100644 (file)
@@ -45,7 +45,33 @@ namespace System.Threading.RateLimiting
         /// <param name="options">Options to specify the behavior of the <see cref="TokenBucketRateLimiter"/>.</param>
         public TokenBucketRateLimiter(TokenBucketRateLimiterOptions options)
         {
-            _options = options ?? throw new ArgumentNullException(nameof(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.", nameof(options));
+            }
+            if (options.QueueLimit < 0)
+            {
+                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
+            {
+                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();
index 6c644ef..c3f29c1 100644 (file)
@@ -9,68 +9,31 @@ namespace System.Threading.RateLimiting
     public sealed class TokenBucketRateLimiterOptions
     {
         /// <summary>
-        /// Initializes the <see cref="TokenBucketRateLimiterOptions"/>.
-        /// </summary>
-        /// <param name="tokenLimit">Maximum number of tokens that can be in the token bucket.</param>
-        /// <param name="queueProcessingOrder"></param>
-        /// <param name="queueLimit">Maximum number of unprocessed tokens waiting via <see cref="RateLimiter.WaitAndAcquireAsync(int, CancellationToken)"/>.</param>
-        /// <param name="replenishmentPeriod">
-        /// Specifies how often tokens can be replenished. Replenishing is triggered either by an internal timer if <paramref name="autoReplenishment"/> is true, or by calling <see cref="TokenBucketRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <param name="tokensPerPeriod">Specified how many tokens can be added to the token bucket on a successful replenish. Available token count will not exceed <paramref name="tokenLimit"/>.</param>
-        /// <param name="autoReplenishment">
-        /// Specifies whether token replenishment will be handled by the <see cref="TokenBucketRateLimiter"/> or by another party via <see cref="TokenBucketRateLimiter.TryReplenish"/>.
-        /// </param>
-        /// <exception cref="ArgumentOutOfRangeException">When <paramref name="tokenLimit"/>, <paramref name="queueLimit"/>, or <paramref name="tokensPerPeriod"/> are less than 0.</exception>
-        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;
-        }
-
-        /// <summary>
         /// Specifies the minimum period between replenishments.
+        /// Must be set to a value >= <see cref="TimeSpan.Zero" /> by the time these options are passed to the constructor of <see cref="TokenBucketRateLimiter"/>.
         /// </summary>
-        public TimeSpan ReplenishmentPeriod { get; }
+        public TimeSpan ReplenishmentPeriod { get; set; } = TimeSpan.Zero;
 
         /// <summary>
         /// Specifies the maximum number of tokens to restore each replenishment.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="TokenBucketRateLimiter"/>.
         /// </summary>
-        public int TokensPerPeriod { get; }
+        public int TokensPerPeriod { get; set; }
 
         /// <summary>
         /// Specified whether the <see cref="TokenBucketRateLimiter"/> is automatically replenishing tokens or if someone else
         /// will be calling <see cref="TokenBucketRateLimiter.TryReplenish"/> to replenish tokens.
         /// </summary>
-        public bool AutoReplenishment { get; }
+        /// <value>
+        /// <see langword="true" /> by default.
+        /// </value>
+        public bool AutoReplenishment { get; set; } = true;
 
         /// <summary>
         /// Maximum number of tokens that can be in the bucket at any time.
+        /// Must be set to a value > 0 by the time these options are passed to the constructor of <see cref="TokenBucketRateLimiter"/>.
         /// </summary>
-        public int TokenLimit { get; }
+        public int TokenLimit { get; set; }
 
         /// <summary>
         /// Determines the behaviour of <see cref="RateLimiter.WaitAndAcquireAsync"/> when not enough resources can be leased.
@@ -78,11 +41,12 @@ namespace System.Threading.RateLimiting
         /// <value>
         /// <see cref="QueueProcessingOrder.OldestFirst"/> by default.
         /// </value>
-        public QueueProcessingOrder QueueProcessingOrder { get; }
+        public QueueProcessingOrder QueueProcessingOrder { get; set; } = QueueProcessingOrder.OldestFirst;
 
         /// <summary>
         /// Maximum cumulative token count of queued acquisition requests.
+        /// Must be set to a value >= 0 by the time these options are passed to the constructor of <see cref="TokenBucketRateLimiter"/>.
         /// </summary>
-        public int QueueLimit { get; }
+        public int QueueLimit { get; set; }
     }
 }
index c0fc937..b5dbd18 100644 (file)
@@ -30,11 +30,23 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter1 = PartitionedRateLimiter.Create<string, int>(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<string, int>(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<string>(limiter1, limiter2);
 
@@ -50,11 +62,23 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter1 = PartitionedRateLimiter.Create<string, int>(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<string, int>(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<string>(limiter1, limiter2);
 
@@ -70,15 +94,33 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter1 = PartitionedRateLimiter.Create<string, int>(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<string, int>(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<string, int>(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<string>(limiter1, limiter2, limiter3);
@@ -90,7 +132,13 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter = PartitionedRateLimiter.Create<string, int>(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<string>(limiter);
@@ -184,8 +232,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -210,8 +268,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -236,7 +304,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter);
@@ -255,7 +328,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter);
@@ -275,7 +353,12 @@ namespace System.Threading.RateLimiting.Tests
         public void AcquireFailsWhenOneLimiterDoesNotHaveEnoughResources()
         {
             var limiterFactory = new TrackingRateLimiterFactory<int>();
-            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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key));
@@ -301,7 +384,12 @@ namespace System.Threading.RateLimiting.Tests
         public async Task WaitAndAcquireAsyncFailsWhenOneLimiterDoesNotHaveEnoughResources()
         {
             var limiterFactory = new TrackingRateLimiterFactory<int>();
-            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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => limiterFactory.GetLimiter(key));
@@ -326,8 +414,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -350,8 +448,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -374,7 +482,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter);
@@ -392,7 +505,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter);
@@ -445,7 +563,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() });
@@ -466,7 +589,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() });
@@ -487,7 +615,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() });
@@ -513,7 +646,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask<RateLimitLease>(new ThrowDisposeLease()) });
@@ -539,7 +677,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() });
@@ -566,7 +709,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask<RateLimitLease>(new ThrowDisposeLease()) });
@@ -593,7 +741,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { AcquireCoreImpl = _ => new ThrowDisposeLease() });
@@ -617,7 +770,12 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => new CustomizableLimiter() { WaitAndAcquireAsyncCoreImpl = (_, _) => new ValueTask<RateLimitLease>(new ThrowDisposeLease()) });
@@ -641,8 +799,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -666,8 +834,18 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter1);
@@ -751,7 +929,12 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter = PartitionedRateLimiter.Create<string, int>(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<string>(limiter);
 
@@ -768,14 +951,24 @@ namespace System.Threading.RateLimiting.Tests
         [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<string, int>(resource =>
             {
                 return RateLimitPartition.Get(1, key => concurrencyLimiter);
             });
             using var limiter2 = PartitionedRateLimiter.Create<string, int>(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<string>(limiter1, limiter2);
 
@@ -797,13 +990,23 @@ namespace System.Threading.RateLimiting.Tests
         {
             using var limiter1 = PartitionedRateLimiter.Create<string, int>(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<string, int>(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<string>(limiter1, limiter2);
 
index bd65b91..ec6fac7 100644 (file)
@@ -11,14 +11,29 @@ namespace System.Threading.RateLimiting.Test
         [Fact]
         public override void InvalidOptionsThrows()
         {
-            Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrencyLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1));
-            Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1));
+            Assert.Throws<ArgumentException>(() => new ConcurrencyLimiter(new ConcurrencyLimiterOptions
+            {
+                PermitLimit = -1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1
+            }));
+            Assert.Throws<ArgumentException>(() => new ConcurrencyLimiter(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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(() => limiter.Acquire(2));
             Assert.Equal("permitCount", ex.ParamName);
         }
@@ -222,7 +287,12 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(async () => await limiter.WaitAndAcquireAsync(2));
             Assert.Equal("permitCount", ex.ParamName);
         }
@@ -230,21 +300,36 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 = 2
+            });
             using var lease = await limiter.WaitAndAcquireAsync(2);
             Assert.True(lease.IsAcquired);
 
@@ -309,7 +414,12 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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 @@ namespace System.Threading.RateLimiting.Test
         [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);
index 0c0063a..0f4b6bf 100644 (file)
@@ -12,8 +12,14 @@ namespace System.Threading.RateLimiting.Test
         [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);
@@ -29,17 +35,46 @@ namespace System.Threading.RateLimiting.Test
         [Fact]
         public override void InvalidOptionsThrows()
         {
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new FixedWindowRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), autoReplenishment: false));
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new FixedWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), autoReplenishment: false));
+            Assert.Throws<ArgumentException>(
+                () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions
+            {
+                PermitLimit = -1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                Window = TimeSpan.FromMinutes(2),
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions
+            {
+                PermitLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = -1,
+                Window = TimeSpan.FromMinutes(2),
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions
+            {
+                PermitLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                Window = TimeSpan.MinValue,
+                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 +90,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +124,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +160,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +180,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +206,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +238,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +265,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +294,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +323,70 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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 +395,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +414,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +430,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +453,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +481,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +508,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +534,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +563,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +578,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +593,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +626,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +659,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +685,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +710,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +731,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +747,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +765,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +794,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +826,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +854,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +881,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +896,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +913,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +930,26 @@ namespace System.Threading.RateLimiting.Test
         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 +957,14 @@ namespace System.Threading.RateLimiting.Test
         [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 +996,14 @@ namespace System.Threading.RateLimiting.Test
         [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);
 
index 2cb4cff..79dd86d 100644 (file)
@@ -133,7 +133,12 @@ namespace System.Threading.RateLimiting.Tests
                     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 @@ namespace System.Threading.RateLimiting.Tests
             using var limiter = PartitionedRateLimiter.Create<string, int>(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 @@ namespace System.Threading.RateLimiting.Tests
             {
                 // 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 @@ namespace System.Threading.RateLimiting.Tests
                 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 @@ namespace System.Threading.RateLimiting.Tests
             using var limiter = PartitionedRateLimiter.Create<string, int>(resource =>
             {
                 return RateLimitPartition.GetConcurrencyLimiter(1,
-                    _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1));
+                    _ => new ConcurrencyLimiterOptions
+                {
+                    PermitLimit = 1,
+                    QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                    QueueLimit = 1
+                });
             });
 
             var lease = limiter.Acquire("");
@@ -600,12 +642,22 @@ namespace System.Threading.RateLimiting.Tests
                 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
+                    });
                 }
             });
 
@@ -639,12 +691,22 @@ namespace System.Threading.RateLimiting.Tests
                 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
+                    });
                 }
             });
 
@@ -678,12 +740,22 @@ namespace System.Threading.RateLimiting.Tests
                 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 +798,22 @@ namespace System.Threading.RateLimiting.Tests
                 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
+                    });
                 }
             });
 
@@ -758,12 +840,22 @@ namespace System.Threading.RateLimiting.Tests
                 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
+                    });
                 }
             });
 
index 4987ab3..be797b1 100644 (file)
@@ -11,7 +11,12 @@ namespace System.Threading.RateLimiting.Tests
         [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 @@ namespace System.Threading.RateLimiting.Tests
         [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 @@ namespace System.Threading.RateLimiting.Tests
         [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<ConcurrencyLimiter>(limiter);
             Assert.Equal(1, concurrencyLimiter.GetAvailablePermits());
 
-            var partition2 = RateLimitPartition.Get(1, key => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 10, TimeSpan.FromMilliseconds(100), 1, autoReplenishment: false)));
+            var partition2 = RateLimitPartition.Get(1, key => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
+            {
+                TokenLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 10,
+                ReplenishmentPeriod = TimeSpan.FromMilliseconds(100),
+                TokensPerPeriod = 1,
+                AutoReplenishment = false
+            }));
             limiter = partition2.Factory(1);
             var tokenBucketLimiter = Assert.IsType<TokenBucketRateLimiter>(limiter);
             Assert.Equal(1, tokenBucketLimiter.GetAvailablePermits());
@@ -74,7 +100,14 @@ namespace System.Threading.RateLimiting.Tests
         [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 @@ namespace System.Threading.RateLimiting.Tests
         [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);
index ff838e9..a582cc0 100644 (file)
@@ -12,8 +12,15 @@ namespace System.Threading.RateLimiting.Test
         [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);
@@ -30,19 +37,60 @@ namespace System.Threading.RateLimiting.Test
         [Fact]
         public override void InvalidOptionsThrows()
         {
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new SlidingWindowRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false));
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false));
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new SlidingWindowRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), -1, autoReplenishment: false));
+            Assert.Throws<ArgumentException>(
+                () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
+            {
+                PermitLimit = -1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                Window = TimeSpan.FromMinutes(2),
+                SegmentsPerWindow = 1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
+            {
+                PermitLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = -1,
+                Window = TimeSpan.FromMinutes(2),
+                SegmentsPerWindow = 1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
+            {
+                PermitLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                Window = TimeSpan.FromMinutes(2),
+                SegmentsPerWindow = -1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
+            {
+                PermitLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                Window = TimeSpan.MinValue,
+                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 +116,15 @@ namespace System.Threading.RateLimiting.Test
             // 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 +154,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +193,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +233,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +252,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +280,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +314,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +343,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +380,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +411,75 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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 +488,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +508,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +525,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +550,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +580,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +608,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +635,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +668,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +684,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +700,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +734,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +768,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +785,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +804,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +838,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +876,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +906,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +935,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +951,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +969,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +988,28 @@ namespace System.Threading.RateLimiting.Test
         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 +1017,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1058,15 @@ namespace System.Threading.RateLimiting.Test
         [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);
 
index 14232bf..9bfeac0 100644 (file)
@@ -12,8 +12,15 @@ namespace System.Threading.RateLimiting.Test
         [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);
@@ -29,19 +36,60 @@ namespace System.Threading.RateLimiting.Test
         [Fact]
         public override void InvalidOptionsThrows()
         {
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new TokenBucketRateLimiterOptions(-1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false));
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, -1, TimeSpan.FromMinutes(2), 1, autoReplenishment: false));
-            Assert.Throws<ArgumentOutOfRangeException>(
-                () => new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, TimeSpan.FromMinutes(2), -1, autoReplenishment: false));
+            Assert.Throws<ArgumentException>(
+                () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
+            {
+                TokenLimit = -1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                ReplenishmentPeriod = TimeSpan.FromMinutes(2),
+                TokensPerPeriod = 1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
+            {
+                TokenLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = -1,
+                ReplenishmentPeriod = TimeSpan.FromMinutes(2),
+                TokensPerPeriod = 1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
+            {
+                TokenLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                ReplenishmentPeriod = TimeSpan.FromMinutes(2),
+                TokensPerPeriod = -1,
+                AutoReplenishment = false
+            }));
+            Assert.Throws<ArgumentException>(
+                () => new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
+            {
+                TokenLimit = 1,
+                QueueProcessingOrder = QueueProcessingOrder.NewestFirst,
+                QueueLimit = 1,
+                ReplenishmentPeriod = TimeSpan.MinValue,
+                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 +105,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +140,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +178,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +199,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +226,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +260,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +288,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +318,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +348,75 @@ namespace System.Threading.RateLimiting.Test
         [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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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<ArgumentOutOfRangeException>(() => 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<ArgumentOutOfRangeException>(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 +425,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +445,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +462,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +486,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +515,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +543,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +583,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +609,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +636,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +666,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +682,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +698,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +732,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +766,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +793,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +818,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +843,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +868,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +890,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +913,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +930,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +947,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +966,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +996,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1029,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1058,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1088,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1128,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1144,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1162,15 @@ namespace System.Threading.RateLimiting.Test
         [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 +1180,28 @@ namespace System.Threading.RateLimiting.Test
         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);
         }