-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPollyRateLimiterHandler.cs
More file actions
57 lines (49 loc) · 2.11 KB
/
PollyRateLimiterHandler.cs
File metadata and controls
57 lines (49 loc) · 2.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.RateLimiting;
using System.Threading.Tasks;
using Polly;
using Polly.RateLimiting;
namespace ZibStack.NET.Aop;
/// <summary>
/// Handler for <see cref="PollyRateLimiterAttribute"/>. Creates a fixed window rate limiter
/// per method and caches it.
/// </summary>
public sealed class PollyRateLimiterHandler : IAroundAspectHandler, IAsyncAroundAspectHandler
{
private static readonly ConcurrentDictionary<string, ResiliencePipeline> PipelineCache = new();
/// <inheritdoc />
public object? Around(AspectContext context, Func<object?> proceed)
{
var pipeline = GetPipeline(context);
return pipeline.Execute(_ => proceed(), CancellationToken.None);
}
/// <inheritdoc />
public async ValueTask<object?> AroundAsync(AspectContext context, Func<ValueTask<object?>> proceed)
{
var pipeline = GetPipeline(context);
return await pipeline.ExecuteAsync(
async ct => await proceed().ConfigureAwait(false),
CancellationToken.None).ConfigureAwait(false);
}
private static ResiliencePipeline GetPipeline(AspectContext context)
{
var permitLimit = 100;
var windowSeconds = 60;
var queueLimit = 0;
if (context.Properties.TryGetValue("PermitLimit", out var pl) && pl is int p) permitLimit = p;
if (context.Properties.TryGetValue("WindowSeconds", out var ws) && ws is int w) windowSeconds = w;
if (context.Properties.TryGetValue("QueueLimit", out var ql) && ql is int q) queueLimit = q;
var cacheKey = $"rl:{context.ClassName}.{context.MethodName}:{permitLimit}:{windowSeconds}:{queueLimit}";
return PipelineCache.GetOrAdd(cacheKey, _ =>
new ResiliencePipelineBuilder()
.AddRateLimiter(new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions
{
PermitLimit = permitLimit,
Window = TimeSpan.FromSeconds(windowSeconds),
QueueLimit = queueLimit,
}))
.Build());
}
}