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

[API Proposal]: Add leaveOpen concept to PartitionedRateLimiter.TranslateKey #72551

Closed
BrennanConroy opened this issue Jul 20, 2022 · 2 comments · Fixed by #73160
Closed

[API Proposal]: Add leaveOpen concept to PartitionedRateLimiter.TranslateKey #72551

BrennanConroy opened this issue Jul 20, 2022 · 2 comments · Fixed by #73160
Labels
api-approved API was approved in API review, it can be implemented area-System.Threading
Milestone

Comments

@BrennanConroy
Copy link
Member

BrennanConroy commented Jul 20, 2022

Background and motivation

Originally proposed and approved in #65400 (comment), the PartitionedRateLimiter<TResource>.TranslateKey(...) method wraps and returns a new instance of PartitionedRateLimiter. Currently we are assuming no ownership of the wrapped limiter to be on the safe side. The proposal is to add a flag to give ownership to the wrapper so Dispose and DisposeAsync will cleanup the wrapped limiter.

A few examples of prior-art for this type of API:

public SslStream(Stream innerStream, bool leaveInnerStreamOpen)

public StreamWriter(Stream stream, Encoding? encoding = null, int bufferSize = -1, bool leaveOpen = false)

public virtual Stream AsStream(bool leaveOpen = false)

API Proposal

namespace System.Threading.RateLimiting;

public abstract class PartitionedRateLimiter<TResource> : IAsyncDisposable, IDisposable
{
-    public PartitionedRateLimiter<TOuter> TranslateKey<TOuter>(Func<TOuter, TResource> keyAdapter);
+    public PartitionedRateLimiter<TOuter> TranslateKey<TOuter>(Func<TOuter, TResource> keyAdapter, bool leaveOpen = false);
}

API Usage

var limiter = PartitionedRateLimiter.Create<string, int>(resource =>
{
    if (resource == "1")
    {
        return RateLimitPartition.GetConcurrencyLimiter(1,
            _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1));
    }
    return RateLimitPartition.GetNoLimiter(2);
});

var translateLimiter = limiter.TranslateKey<int>(i => i.ToString(), leaveOpen: false);
translateLimiter.Acquire(1);

translateLimiter.Dispose();

Alternative Designs

Leave as-is and require user to keep track of the inner limiter and call Dispose/DisposeAsync on that when done.

Risks

If more options are added for TranslateKey then we'll end up with additional overloads. Like how StreamWriter and SslStream have a bunch of overloads.

I am unable to think of options we might want to add in the future though.

@BrennanConroy BrennanConroy added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Threading blocking Marks issues that we want to fast track in order to unblock other important work labels Jul 20, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jul 20, 2022
@ghost
Copy link

ghost commented Jul 20, 2022

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

Originally proposed and approved in #65400 (comment), the PartitionedRateLimiter<TResource>.TranslateKey(...) method wraps and returns a new instance of PartitionedRateLimiter. Currently we are assuming no ownership of the wrapped limiter to be on the safe side. The proposal is to add a flag to give ownership to the wrapper so Dispose and DisposeAsync will cleanup the inner limiter.

A few examples of prior-art for this type of API:

public SslStream(Stream innerStream, bool leaveInnerStreamOpen)

public StreamWriter(Stream stream, Encoding? encoding = null, int bufferSize = -1, bool leaveOpen = false)

public virtual Stream AsStream(bool leaveOpen = false)

API Proposal

namespace System.Threading.RateLimiting;

public abstract class PartitionedRateLimiter<TResource> : IAsyncDisposable, IDisposable
{
-    public PartitionedRateLimiter<TOuter> TranslateKey<TOuter>(Func<TOuter, TResource> keyAdapter);
+    public PartitionedRateLimiter<TOuter> TranslateKey<TOuter>(Func<TOuter, TResource> keyAdapter, bool leaveOpen = false);
}

API Usage

var limiter = PartitionedRateLimiter.Create<string, int>(resource =>
{
    if (resource == "1")
    {
        return RateLimitPartition.GetConcurrencyLimiter(1,
            _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1));
    }
    return RateLimitPartition.GetNoLimiter(2);
});

var translateLimiter = limiter.TranslateKey<int>(i => i.ToString(), leaveOpen: false);
translateLimiter.Acquire(1);

translateLimiter.Dispose();

Alternative Designs

Leave as-is and require user to keep track of the inner limiter and call Dispose/DisposeAsync on that when done.

Risks

If more options are added for TranslateKey then we'll end up with additional overloads. Like how StreamWriter and SslStream have a bunch of overloads.

I am unable to think of options we might want to add in the future though.

Author: BrennanConroy
Assignees: -
Labels:

api-suggestion, area-System.Threading, blocking

Milestone: -

@BrennanConroy BrennanConroy added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels Jul 20, 2022
@mangod9 mangod9 removed the untriaged New issue has not been triaged by the area owner label Jul 25, 2022
@mangod9 mangod9 added this to the 7.0.0 milestone Jul 25, 2022
@terrajobst
Copy link
Member

terrajobst commented Jul 26, 2022

Video

  • Let's make the parameter explicit to ensure people understand the transfer of ownership
    • Let's also rename it to WithTranslatedKey
namespace System.Threading.RateLimiting;

public abstract class PartitionedRateLimiter<TResource> : IAsyncDisposable, IDisposable
{
-    public PartitionedRateLimiter<TOuter> TranslateKey<TOuter>(Func<TOuter, TResource> keyAdapter);
+    public PartitionedRateLimiter<TOuter> WithTranslatedKey<TOuter>(Func<TOuter, TResource> keyAdapter, bool leaveOpen);
}

@terrajobst terrajobst added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Jul 26, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Aug 1, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Aug 12, 2022
@BrennanConroy BrennanConroy removed the blocking Marks issues that we want to fast track in order to unblock other important work label Aug 12, 2022
@dotnet dotnet locked as resolved and limited conversation to collaborators Sep 11, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Threading
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants