Skip to content
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

ConcurrencyLimiter implementation #387

Merged
merged 5 commits into from
Oct 26, 2021
Merged

Conversation

BrennanConroy
Copy link
Member

No description provided.

lock (_lock)
{
// REVIEW: failed lease or exception?
tcs.TrySetResult(FailedLease);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a OperationCanceledException/TaskCanceledException or a failed lease with a reason phrase?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably capture the CancellationToken when we UnsafeRegister and either call tcs.TrySetCanceled(token) or tcs.TrySetException(new OperationCanceledException(token)). I don't have a big preference for which one. CancellationToken.ThrowIfCancellationRequested() throws an OperationCanceledException though, and we should probably be doing that at the start of WaitAsyncCore, so maybe we should use an OperationCanceledExceptoin for consistency.

@@ -27,6 +42,7 @@ public bool TryGetMetadata<T>(MetadataName<T> metadataName, [MaybeNullWhen(false
var successful = TryGetMetadata(metadataName.Name, out var rawMetadata);
if (successful)
{
// TODO: is null metadata allowed?
metadata = rawMetadata is null ? default : (T)rawMetadata;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think null metadata should be allowed when returning true. I think in API review we decided T should not be nullable. MaybeNullWhen should only apply to non-nullable attributes anyway. If this was supposed to be nullable, we'd use [NotNullWhen(true)].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API review also said a null metadata is valid, but how do you represent that in generic code? Do we just hide the compiler warning?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't recall API review saying null metadata was valid except when TryGetMetadata returns false, but the signatures of the non-generic TryGetMetadata and GetAllMetadata make me wonder.

There shouldn't be a compiler warning since we're using [MaybeNullWhen(false)].

Specifies that when a method returns ReturnValue, the parameter may be null even if the corresponding type disallows it.

Emphasis mine. The signature in the API proposal is public bool TryGetMetadata<T>(MetadataName<T> metadataName, [MaybeNullWhen(false)] out T metadata); with no T?.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I might remember us discussing allowing null to distinguish between metadata that is normally defined but not present (returns true but gives null) vs metadata that is never present (returns false and gives null). If that's the case, the signature should probably just be public bool TryGetMetadata<T>(MetadataName<T> metadataName, [MaybeNull] out T metadata). This way value types don't need to be wrapped in Nullable.

src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
{
throw new ArgumentOutOfRangeException();
throw new InvalidOperationException($"{permitCount} permits exceeds the permit limit of {_options.PermitLimit}.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Since I can't unresolve the previous conversation, starting a new one here)

I'm not sure I buy the above analysis (I know it came from API review). Looking at the Example of ArgumentOutOfRangeException in the docs doesn't follow this reasoning. There is no property that specifies a "min age" in that example.

Same goes for the wording on https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/using-standard-exception-types#argumentexception-argumentnullexception-and-argumentoutofrangeexception.

if bad arguments are passed to a member

Lastly, the base RateLimiter.WaitAsync xml doc documents the ArgumentOutOfRangeException. But it doesn't document InvalidOperationException. Following the same reasoning as above, a caller to RateLimiter.WaitAsync wouldn't know to catch InvalidOperationException if it passed in too big of a permitCount.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your arguments and will revert back to ArgumentOutOfRangeException with an error message

src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
src/RateLimiting/src/ConcurrencyLimiter.cs Outdated Show resolved Hide resolved
Copy link

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@halter73 halter73 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants