-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add RateLimiting APIs #61788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RateLimiting APIs #61788
Conversation
|
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
|
Tagging subscribers to this area: @mangod9 Issue DetailsPart of dotnet/aspnetcore#37385 There were a couple minor code fixups needed for building in the repo because the project now targets more TFMs than just netstandard2.0. I will call out the changes in code review comments. Couple things to note:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added = default; since the compiler doesn't like you using non-initialized variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ! to obj, to fix nullable warning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of cancellationToken in the delegate is causing this method to always allocate a closure, even on the fast paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ? since IEquatable requires it, and added the if (other is null) check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added = default;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ! to obj
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue here with regards to a closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to private and use reflection in tests to avoid IVT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to reflection to call private method instead of IVT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These non-synchronized fast-path checks mean we might return failure even if success is possible. That's ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine, it's an implicit race, locking would still race with someone releasing permits at the same time.
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/Internal/Deque.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/MetadataName.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/MetadataName.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitLease.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitLease.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitLease.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.csproj
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/tests/System.Threading.RateLimiting.Tests.csproj
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/MetadataName.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/tests/Internal/TaskExtensions.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approved API called these:
ProcessOldest,
ProcessNewest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approved API code was wrong, the comment above the code states:
We decided to rename the QueueProcessingOrder members from { ProcessOldest, ProcessNewest } to { OldestFirst, NewestFirst }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't metadata be attributed with [MaybeNullWhen(false)]?
What does it mean to return true from TryGetMetadata, but the metadata still being null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During one of the reviews it was discussed that a null value could be valid metadata
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember discussing wanting to distinguish between metadata that is sometimes defined but not present (returns true but gives null) vs metadata that is never present (returns false).
Previous discussion: #52079 (comment)
src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimitLease.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This description is different than ConcurrencyLimiterOptions:
/// Maximum number of permits that can be queued concurrently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done on purpose. The API review called out that TokenBucket should refer to permits as tokens where possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it odd that we have RateLimiter, TokenBucketRateLimiter, but then ConcurrencyLimiter? Why not ConcurrencyRateLimiter?
martincostello
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've had a rate-limiting prototype sitting around in Polly for a while (App-vNext/Polly#666) so I thought I'd take a look at this - looks nice.
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
...ries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/QueueProcessingOrder.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...em.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs
Outdated
Show resolved
Hide resolved
...em.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiterOptions.cs
Outdated
Show resolved
Hide resolved
2010f64 to
f59ff02
Compare
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Show resolved
Hide resolved
...es/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs
Outdated
Show resolved
Hide resolved
...raries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Threading.RateLimiting/ref/System.Threading.RateLimiting.cs
Outdated
Show resolved
Hide resolved
eerhardt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiter.cs
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| // Return SuccessfulLease or FailedLease to indicate limiter state | ||
| if (permitCount == 0 && !_disposed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to throw ObjectDisposedException if this has been disposed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should an ODE throw synchronously or be wrapped in a ValueTask?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the first question is:
- Do we want to throw ODE or always return "failed" when a limiter is disposed?
Doing a quick check of other System.Threading disposable types, they seem to throw ODE: Barrier, ManualResetEventSlim, ReaderWriterLockSlim
For the next question, I would say it is similar to argument checking - so we would throw inline.
Part of dotnet/aspnetcore#37385
Moves the current non-generic APIs and two rate limiter implementations from https://github.com/aspnet/AspLabs/tree/main/src/RateLimiting.
There were a couple minor code fixups needed for building in the repo because the project now targets more TFMs than just netstandard2.0. I will call out the changes in code review comments.
Couple things to note:
TaskExtensions.DefaultTimeout()methods from asplabs/aspnetcore that we use in our tests to detect hangs/prevent hangs on the CI. Not sure how the Runtime handles test hangs as I haven't seen tests do anything special with awaiting tasks.<IsPackable>or any other metadata?