-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new issue that demonstrates how to use PartitionedRateLimiter
- Loading branch information
Showing
2 changed files
with
81 additions
and
0 deletions.
There are no files selected for viewing
80 changes: 80 additions & 0 deletions
80
test/Polly.Extensions.Tests/Issues/IssuesTests.PartitionedRateLimiter_1365.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using System.Threading.RateLimiting; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Polly.RateLimiting; | ||
using Polly.Registry; | ||
|
||
namespace Polly.Extensions.Tests.Issues; | ||
|
||
public partial class IssuesTests | ||
{ | ||
/// <summary> | ||
/// This test demonstrates how to use <see cref="PartitionedRateLimiter"/> to rate-limit the individual users. | ||
/// Additionally, it also shows how to disable rate limiting for admin users. | ||
/// </summary> | ||
[Fact] | ||
public async void PartitionedRateLimiter_EnsureUserLimited_1365() | ||
{ | ||
// arrange | ||
var userKey = new ResiliencePropertyKey<string>("user"); | ||
var services = new ServiceCollection(); | ||
services | ||
.AddResilienceStrategy("shared-limiter", (builder, context) => | ||
{ | ||
var partitionedLimiter = PartitionedRateLimiter.Create<ResilienceContext, string>(context => | ||
{ | ||
// you can use `context.ServiceProvider` to resolve whatever service you | ||
// want form DI such as `IHttpContextAccessor` and use it here to resolve | ||
// any information from HttpContext | ||
if (!context.Properties.TryGetValue(userKey, out var user) || user == "admin") | ||
{ | ||
return RateLimitPartition.GetNoLimiter("none"); | ||
} | ||
return RateLimitPartition.GetConcurrencyLimiter(user, key => new ConcurrencyLimiterOptions { PermitLimit = 2, QueueLimit = 0 }); | ||
}); | ||
builder.AddRateLimiter(new RateLimiterStrategyOptions | ||
{ | ||
RateLimiter = ResilienceRateLimiter.Create(partitionedLimiter) | ||
}); | ||
}); | ||
|
||
var serviceProvider = services.BuildServiceProvider(); | ||
var strategy = serviceProvider.GetRequiredService<ResilienceStrategyProvider<string>>().GetStrategy("shared-limiter"); | ||
|
||
// assert user is limited | ||
using var asserted = new ManualResetEvent(false); | ||
await Assert.ThrowsAsync<RateLimiterRejectedException>(() => ExecuteBatch("guest-user", asserted)); | ||
asserted.Set(); | ||
|
||
// assert admin is not limited | ||
using var adminAsserted = new ManualResetEvent(false); | ||
var task = ExecuteBatch("admin", adminAsserted); | ||
task.Wait(100).Should().BeFalse(); | ||
adminAsserted.Set(); | ||
await task; | ||
|
||
async Task ExecuteBatch(string user, ManualResetEvent waitAsserted) | ||
{ | ||
var tasks = Enumerable.Repeat(0, 10).Select(_ => | ||
{ | ||
return Task.Run(async () => | ||
{ | ||
var context = ResilienceContext.Get(); | ||
context.Properties.Set(userKey, user); | ||
await strategy.ExecuteAsync(async _ => | ||
{ | ||
await Task.Yield(); | ||
waitAsserted.WaitOne(); | ||
}, | ||
context); | ||
}); | ||
}).ToArray(); | ||
|
||
var finished = await Task.WhenAny(tasks); | ||
await finished; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters