Skip to content

Commit 9c37a3b

Browse files
Add Fixed and Sliding Window RateLimiters + PartitionedRateLimiter.Create (#68695)
* Add RL non-generic fixed window, sliding window implementations (#68087) * Add initial impl of PartitionedRateLimiter.Create (#67677) Co-authored-by: Shreya Verma <[email protected]>
1 parent 083181f commit 9c37a3b

21 files changed

+3792
-6
lines changed

src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs

+64
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public MetadataName(string name) { }
4040
public static bool operator !=(System.Threading.RateLimiting.MetadataName<T> left, System.Threading.RateLimiting.MetadataName<T> right) { throw null; }
4141
public override string ToString() { throw null; }
4242
}
43+
public static partial class PartitionedRateLimiter
44+
{
45+
public static System.Threading.RateLimiting.PartitionedRateLimiter<TResource> Create<TResource, TPartitionKey>(System.Func<TResource, System.Threading.RateLimiting.RateLimitPartition<TPartitionKey>> partitioner, System.Collections.Generic.IEqualityComparer<TPartitionKey>? equalityComparer = null) where TPartitionKey : notnull { throw null; }
46+
}
4347
public abstract partial class PartitionedRateLimiter<TResource> : System.IAsyncDisposable, System.IDisposable
4448
{
4549
protected PartitionedRateLimiter() { }
@@ -83,6 +87,21 @@ protected virtual void Dispose(bool disposing) { }
8387
public abstract bool TryGetMetadata(string metadataName, out object? metadata);
8488
public bool TryGetMetadata<T>(System.Threading.RateLimiting.MetadataName<T> metadataName, [System.Diagnostics.CodeAnalysis.MaybeNullAttribute] out T metadata) { throw null; }
8589
}
90+
public static partial class RateLimitPartition
91+
{
92+
public static System.Threading.RateLimiting.RateLimitPartition<TKey> CreateConcurrencyLimiter<TKey>(TKey partitionKey, System.Func<TKey, System.Threading.RateLimiting.ConcurrencyLimiterOptions> factory) { throw null; }
93+
public static System.Threading.RateLimiting.RateLimitPartition<TKey> CreateNoLimiter<TKey>(TKey partitionKey) { throw null; }
94+
public static System.Threading.RateLimiting.RateLimitPartition<TKey> CreateTokenBucketLimiter<TKey>(TKey partitionKey, System.Func<TKey, System.Threading.RateLimiting.TokenBucketRateLimiterOptions> factory) { throw null; }
95+
public static System.Threading.RateLimiting.RateLimitPartition<TKey> Create<TKey>(TKey partitionKey, System.Func<TKey, System.Threading.RateLimiting.RateLimiter> factory) { throw null; }
96+
}
97+
public partial struct RateLimitPartition<TKey>
98+
{
99+
private readonly TKey _PartitionKey_k__BackingField;
100+
private object _dummy;
101+
private int _dummyPrimitive;
102+
public RateLimitPartition(TKey partitionKey, System.Func<TKey, System.Threading.RateLimiting.RateLimiter> factory) { throw null; }
103+
public readonly TKey PartitionKey { get { throw null; } }
104+
}
86105
public abstract partial class ReplenishingRateLimiter : System.Threading.RateLimiting.RateLimiter
87106
{
88107
protected ReplenishingRateLimiter() { }
@@ -113,4 +132,49 @@ public TokenBucketRateLimiterOptions(int tokenLimit, System.Threading.RateLimiti
113132
public int TokenLimit { get { throw null; } }
114133
public int TokensPerPeriod { get { throw null; } }
115134
}
135+
public sealed partial class SlidingWindowRateLimiter : System.Threading.RateLimiting.ReplenishingRateLimiter
136+
{
137+
public SlidingWindowRateLimiter(System.Threading.RateLimiting.SlidingWindowRateLimiterOptions options) { }
138+
public override System.TimeSpan? IdleDuration { get { throw null; } }
139+
public override bool IsAutoReplenishing { get { throw null; } }
140+
public override System.TimeSpan ReplenishmentPeriod { get { throw null; } }
141+
protected override System.Threading.RateLimiting.RateLimitLease AcquireCore(int requestCount) { throw null; }
142+
protected override void Dispose(bool disposing) { }
143+
protected override System.Threading.Tasks.ValueTask DisposeAsyncCore() { throw null; }
144+
public override int GetAvailablePermits() { throw null; }
145+
public override bool TryReplenish() { throw null; }
146+
protected override System.Threading.Tasks.ValueTask<System.Threading.RateLimiting.RateLimitLease> WaitAsyncCore(int requestCount, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
147+
}
148+
public sealed partial class SlidingWindowRateLimiterOptions
149+
{
150+
public SlidingWindowRateLimiterOptions(int permitLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit, System.TimeSpan window, int segmentsPerWindow, bool autoReplenishment = true) { }
151+
public bool AutoReplenishment { get { throw null; } }
152+
public int QueueLimit { get { throw null; } }
153+
public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } }
154+
public System.TimeSpan Window { get { throw null; } }
155+
public int PermitLimit { get { throw null; } }
156+
public int SegmentsPerWindow { get { throw null; } }
157+
}
158+
public sealed partial class FixedWindowRateLimiter : System.Threading.RateLimiting.ReplenishingRateLimiter
159+
{
160+
public FixedWindowRateLimiter(System.Threading.RateLimiting.FixedWindowRateLimiterOptions options) { }
161+
public override System.TimeSpan? IdleDuration { get { throw null; } }
162+
public override bool IsAutoReplenishing { get { throw null; } }
163+
public override System.TimeSpan ReplenishmentPeriod { get { throw null; } }
164+
protected override System.Threading.RateLimiting.RateLimitLease AcquireCore(int requestCount) { throw null; }
165+
protected override void Dispose(bool disposing) { }
166+
protected override System.Threading.Tasks.ValueTask DisposeAsyncCore() { throw null; }
167+
public override int GetAvailablePermits() { throw null; }
168+
public override bool TryReplenish() { throw null; }
169+
protected override System.Threading.Tasks.ValueTask<System.Threading.RateLimiting.RateLimitLease> WaitAsyncCore(int requestCount, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
170+
}
171+
public sealed partial class FixedWindowRateLimiterOptions
172+
{
173+
public FixedWindowRateLimiterOptions(int permitLimit, System.Threading.RateLimiting.QueueProcessingOrder queueProcessingOrder, int queueLimit, System.TimeSpan window, bool autoReplenishment = true) { }
174+
public bool AutoReplenishment { get { throw null; } }
175+
public int QueueLimit { get { throw null; } }
176+
public System.Threading.RateLimiting.QueueProcessingOrder QueueProcessingOrder { get { throw null; } }
177+
public System.TimeSpan Window { get { throw null; } }
178+
public int PermitLimit { get { throw null; } }
179+
}
116180
}

src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
44
<Nullable>enable</Nullable>
@@ -16,20 +16,30 @@ System.Threading.RateLimiting.RateLimitLease</PackageDescription>
1616
<ItemGroup>
1717
<Compile Include="System\Threading\RateLimiting\ConcurrencyLimiter.cs" />
1818
<Compile Include="System\Threading\RateLimiting\ConcurrencyLimiterOptions.cs" />
19+
<Compile Include="System\Threading\RateLimiting\FixedWindowRateLimiter.cs" />
20+
<Compile Include="System\Threading\RateLimiting\FixedWindowRateLimiterOptions.cs" />
1921
<Compile Include="System\Threading\RateLimiting\MetadataName.cs" />
2022
<Compile Include="System\Threading\RateLimiting\MetadataName.T.cs" />
23+
<Compile Include="System\Threading\RateLimiting\NoopLimiter.cs" />
24+
<Compile Include="System\Threading\RateLimiting\PartitionedRateLimiter.cs" />
2125
<Compile Include="System\Threading\RateLimiting\PartitionedRateLimiter.T.cs" />
2226
<Compile Include="System\Threading\RateLimiting\QueueProcessingOrder.cs" />
2327
<Compile Include="System\Threading\RateLimiting\RateLimiter.cs" />
2428
<Compile Include="System\Threading\RateLimiting\RateLimitLease.cs" />
29+
<Compile Include="System\Threading\RateLimiting\RateLimitPartition.cs" />
30+
<Compile Include="System\Threading\RateLimiting\RateLimitPartition.T.cs" />
2531
<Compile Include="System\Threading\RateLimiting\ReplenishingRateLimiter.cs" />
32+
<Compile Include="System\Threading\RateLimiting\SlidingWindowRateLimiter.cs" />
33+
<Compile Include="System\Threading\RateLimiting\SlidingWindowRateLimiterOptions.cs" />
34+
<Compile Include="System\Threading\RateLimiting\TimerAwaitable.cs" />
2635
<Compile Include="System\Threading\RateLimiting\TokenBucketRateLimiter.cs" />
2736
<Compile Include="System\Threading\RateLimiting\TokenBucketRateLimiterOptions.cs" />
2837
<Compile Include="$(CommonPath)System\Collections\Generic\Deque.cs" Link="Common\System\Collections\Generic\Deque.cs" />
2938
</ItemGroup>
3039
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
3140
<Reference Include="System.Runtime" />
3241
<Reference Include="System.Threading" />
42+
<Reference Include="System.Collections" />
3343
</ItemGroup>
3444
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
3545
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(SystemThreadingTasksExtensionsVersion)" />

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ protected override ValueTask<RateLimitLease> WaitAsyncCore(int permitCount, Canc
112112
RequestRegistration oldestRequest = _queue.DequeueHead();
113113
_queueCount -= oldestRequest.Count;
114114
Debug.Assert(_queueCount >= 0);
115-
oldestRequest.Tcs.TrySetResult(FailedLease);
115+
if (!oldestRequest.Tcs.TrySetResult(FailedLease))
116+
{
117+
// Updating queue count is handled by the cancellation code
118+
_queueCount += oldestRequest.Count;
119+
}
116120
}
117121
while (_options.QueueLimit - _queueCount < permitCount);
118122
}
@@ -249,7 +253,7 @@ protected override void Dispose(bool disposing)
249253
? _queue.DequeueHead()
250254
: _queue.DequeueTail();
251255
next.CancellationTokenRegistration.Dispose();
252-
next.Tcs.SetResult(FailedLease);
256+
next.Tcs.TrySetResult(FailedLease);
253257
}
254258
}
255259
}

0 commit comments

Comments
 (0)