dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

[API Proposal]: RateLimiter uses TimeProvider #106447

Open aetos382 opened 1 month ago

aetos382 commented 1 month ago

Background and motivation

Rate limiters in the System.Threading.RateLimiting namespace is not designed to accept TimeProvider.

Therefore, we need to wait for the actual time to elapse when testing functions that use them.

For faster testing, please make sure that rate limiters accepts TimeProvider and does not have to wait for the actual time to elapse.

API Proposal

namespace System.Threading.RateLimiting;

public sealed class FixedWindowRateLimiterOptions
{
    public TimeProvider TimeProvider { get; set; } = TimeProvider.System;
}

public sealed class SlidingWindowRateLimiterOptions
{
    public TimeProvider TimeProvider { get; set; } = TimeProvider.System;
}

public sealed class TokenBucketRateLimiterOptions
{
    public TimeProvider TimeProvider { get; set; } = TimeProvider.System;
}

API Usage

var timeProvider = new FakeTimeProvider();

var options = new TokenBucketRateLimiterOptions
{
    TokenLimit = 1,
    TokensPerPeriod = 1,
    AutoReplenishment = true,
    ReplenishmentPeriod = TimeSpan.FromSeconds(10),
    TimeProvider = timeProvider
};

using var limiter = new TokenBucketRateLimiter(options);

using (var lease = limiter.AttemptAcquire())
{
    Assert.True(lease.IsAcquired);
}

timeProvider.Advance(TimeSpan.FromSeconds(10));

// If TimeProvider is not supported, we need to actually stop the thread here.
// Thread.Sleep(TimeSpan.FromSeconds(10));

using (var lease = limiter.AttemptAcquire())
{
    Assert.True(lease.IsAcquired);
}

Alternative Designs

No response

Risks

No response

dotnet-policy-service[bot] commented 1 month ago

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