Repository navigation
Open
Labels
area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresdesign-proposalThis issue represents a design proposal for a different issue, linked in the descriptionThis issue represents a design proposal for a different issue, linked in the descriptionfeature-rate-limitWork related to use of rate limit primitivesWork related to use of rate limit primitives
Milestone
Description
Summary
Redis is soon to gain an inbuilt GCRA rate limiter. Support is being added via SE.Redis.
Questions here:
- should this (and can this) be used as an implementation of the asp-net rate-limiting abstraction?
- if "yes" to 1, where should that be? here? or in a Redis-owned package?
Relevant context / disclosure:
- asp-net already has relevant SE.Redis dependencies, but these would need to be rev'd
- I'm the main SE.Redis maintainer
- I work for Redis
- I used to be part of the asp-net team
So: I'm happy to offer my time here towards an implementation, as it fits both my knowledge and objectives. I'm also entirely happy to just say "hey, this API exists; have fun" if people don't want that. But if we do want such an API, then the interesting question is "where?" - would this go "here" alongside the other implementations, or would we want to keep things isolated, i.e. I create a Redis-owned package under the redis org.
I wanted to discuss it before jumping in.
(pinging @DeagleGross and @BrennanConroy just to help me with routing)
Reacted by Korolev Dmitry, Qing Long and Luis von der Eltz
Reacted by Stephen Halter and Luis von der Eltz
Metadata
Metadata
Assignees
Labels
area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresdesign-proposalThis issue represents a design proposal for a different issue, linked in the descriptionThis issue represents a design proposal for a different issue, linked in the descriptionfeature-rate-limitWork related to use of rate limit primitivesWork related to use of rate limit primitives
Activity
mgravell commentedon Mar 16, 2026
Redis command is†
GCRA key max_burst requests_per_period period [NUM_REQUESTS count]; I'm assuming the key here would be post-partitioner, so presumably something along the lines of:There's also the question of whether to support the variable cost aspect (
[NUM_REQUESTS count]defaults to 1, and is the number of tokens consumed by a given request).I'm not precious about anything naming... there might be a "Distributed" or something wanted in there somehows.
†: currently not merged, so: subject to change
DeagleGross commentedon Mar 23, 2026
Hey @mgravell, thanks for sharing plans about GCRA limiter. Just acknowledging we have seen this issue posted, and we'll come back to you once we have more detailed understanding of how we want to build this.
mgravell commentedon Apr 17, 2026
@DeagleGross any updates?
DeagleGross commentedon Apr 20, 2026
@mgravell sorry, was busy handling other stuff - I'll prioritize and hopefully return here this week. Thanks for keeping this in mind!
DeagleGross commentedon Apr 22, 2026
I've spent some time analyzing what pieces we have now, and below is the explanation of thought + proposal for what we probably want for GCRA. I am not as expert'ish as @mgravell with Redis and RateLimiting in general, so please correct me where you think you would make adjustments.
To be fair, since we will probably be only introducing the
Microsoft.AspNetCore.RateLimiting.StackExchangeRedispackage with this GCRA effort, I need to spend time looking into different existing issues in the aspnetcore's ratelimiting space (example is #42691). It will help us build a better API from the get-go, and make less adjustments later I hope.Also in the meantime I'll spin up some conversation with one of the known packages that provide this kind of integration between Redis and AspNetCore: https://github.com/cristipufu/aspnetcore-redis-rate-limiting.
API Proposal: Redis GCRA Rate Limiter
Related: #41861, #53426, #42691
Motivation
ASP.NET Core has a rate limiting middleware (shipped in .NET 7) with four in-process algorithms: fixed window, sliding window, token bucket, and concurrency limiter. All of them store state in-memory, meaning each app server tracks limits independently. With N servers, a client can achieve N× the intended rate by distributing requests across servers.
There is currently no distributed rate limiting support in ASP.NET Core. Issues #41861 and #53426 have been open since 2022/2024 requesting this.
Redis is adding a native GCRA (Generic Cell Rate Algorithm) command. GCRA is uniquely suited for distributed rate limiting because:
max_burstparameter controls burst allowanceremaining,retry_after, andreset_afterin one callStackExchange.Redis is adding client support via
StringGcraRateLimitAsync().Current State of Code
Rate limiting abstractions (dotnet/runtime —
System.Threading.RateLimiting)The runtime provides the abstract base classes and in-process implementations:
Rate limiting middleware (dotnet/aspnetcore —
Microsoft.AspNetCore.RateLimiting)The aspnetcore repo provides middleware integration and convenience APIs:
Existing Redis packages in aspnetcore
ASP.NET Core already ships four packages that depend on
StackExchangeRedis:Microsoft.Extensions.Caching.StackExchangeRedisIDistributedCacheimplementationMicrosoft.AspNetCore.SignalR.StackExchangeRedisMicrosoft.AspNetCore.DataProtection.StackExchangeRedisMicrosoft.AspNetCore.OutputCaching.StackExchangeRedisAll follow the same pattern: a separate NuGet package in the aspnetcore repo that depends on
StackExchange.Redisand implements an ASP.NET Core abstraction backed by Redis.What's missing
There is no distributed
RateLimiterimplementation. The gap:Design Principles
AddRateLimiter(),UseRateLimiter(),RequireRateLimiting()pipeline. Users swap an in-process limiter for a Redis-backed one by changing the registration, not the middleware.Configuration,ConfigurationOptions,ConnectionMultiplexerFactory,InstanceName).RateLimitPartition.Get<TKey>()factory already exists. No new abstractions needed inSystem.Threading.RateLimiting.Architecture
Package:
Microsoft.AspNetCore.RateLimiting.StackExchangeRedisA new package in
src/Middleware/RateLimiting.StackExchangeRedis/following the same structure asMicrosoft.AspNetCore.OutputCaching.StackExchangeRedis.Dependencies:
StackExchange.Redis(NuGet)Microsoft.AspNetCore.RateLimiting(project reference)How it fits the existing pipeline
Middleware flow with Redis GCRA
The existing
RateLimitingMiddlewarehas a two-phase acquire:For Redis GCRA:
AttemptAcquire()→ returns a "not acquired" lease (cannot do sync Redis calls). No permits consumed.AcquireAsync()→ executes the Redis GCRA command.API
New types in
Microsoft.AspNetCore.RateLimiting.StackExchangeRedisExtension methods
Lease metadata
The Redis GCRA response includes
retry_after_s,remaining, andreset_after_s. Rejected leases exposeMetadataName.RetryAfterso theOnRejectedcallback can set theRetry-Afterresponse header:Usage Examples
Global rate limit (all requests share one Redis key)
Per-user rate limit
Mixed: in-process + Redis
Advanced: direct PartitionedRateLimiter usage
For users who want full control (e.g., as a
GlobalLimiter), theRedisGcraRateLimitercan be used with the genericRateLimitPartition.Get<TKey>()factory:Behavioral Details
AttemptAcquire (sync fast path)
RedisGcraRateLimiter.AttemptAcquire()returns a lease withIsAcquired = falsewithout consuming any permits. The middleware'sTryAcquireAsyncmethod then falls back toAcquireAsync, which performs the Redis call. This follows the existing contract —AttemptAcquireis documented as "fast synchronous attempt" and returning a failed lease is valid behavior.Variable cost
The
permitCountparameter fromAcquireAsync(int permitCount)is passed as theTOKENSparameter to the Redis GCRA command. This supports variable-cost scenarios (e.g., a bulk upload costs 10 tokens, a read costs 1) without additional API.mgravell commentedon Apr 22, 2026
Wow, that's a huge piece of analysis; kudos and appreciated. Let me know what I can do to help!
DeagleGross commentedon Apr 27, 2026
@mgravell thanks; I think if you want to explore what kind of specific API you imagine should happen in separate
Microsoft.AspNetCore.RateLimiting.StackExchangeRedispackage - I would be happy to hear your thoughts. I talked to @halter73 and confirmed it seems like we should ship this package. If you dont want to do this experimental work - that is fine, I dont want you to waste your time here.I may not have a lot of time to move this further soon'ish, but hopefully we'll move it to some degree until net11, and I can try to come up with some rough API of the package (MVP branch), where you can see GCRA bits and adjust per your expertise. I'll keep you posted
mgravell commentedon Apr 27, 2026
Awesome. Keep me in the loop. Server 8.8 should be shopping any time soon, although @philon-msft might need to advise on when that ships inside AMR etc. I can point you at docker images for local/CI hosting.
mgravell commentedon May 8, 2026
@DeagleGross well shoot, GCRA got yanked from 8.8; the server team are re-evaluating, and I suspect are planning to replace the feature with something similar but not the same; I think we need to park this for now. Sorry. I'm actively yanking code :(
DeagleGross commentedon May 9, 2026
@mgravell no worries, it is still great you raised this question about having Redis centric library from aspnetcore side. Please, let us know if you see any movement with the GCRA happening, and we can consider working on this for net11 or more realistically for net12 already.
mgravell commentedon May 9, 2026
I believe the plan is to broaden the scope - i.e. GCRA is only a very specific implementation, but rate limiting should be a wider feature with GCRA as but one option. So it might be AGoodThingTM
lqlive commentedon Jun 30, 2026
Hi @DeagleGross, I’ve been working on a small prototype for
Microsoft.AspNetCore.RateLimiting.StackExchangeRedis.Given that the native Redis GCRA command is currently parked, the prototype uses a Lua script for the atomic GCRA operation, but keeps the API aligned with the proposal above.
I pasted the current prototype below only to show the implementation direction, not as a final API proposal.
Would this Lua-based GCRA implementation be an acceptable direction to explore? If so, would you be open to a draft PR for review and API discussion?
DeagleGross commentedon Jul 2, 2026
@lqlive hey, thanks for sharing this prototype.
I think we should create a package like
Microsoft.AspNetCore.RateLimiting.StackExchangeRediswhich depends on https://github.com/StackExchange/stackexchange.redis. As Marc has pointed out GCRA will appear later in Redis, and he will support it in StackExchangeRedis - if that happens, it will be much easier to just reuse API from NuGet package than building from scratch implementation in aspnetcore.However, nobody is stopping you from proposing general API that should exist in
Microsoft.AspNetCore.RateLimiting.StackExchangeRedis- the API should be generic enough to support not only GCRA, but other rate-limiting algorithms as well (theoretically). Then we can pick algorithms one-by-one and include them in the package.Are you specifically interested in GCRA? Please let us know about the scenario you are trying to build the solution for. Thanks!
lqlive commentedon Jul 2, 2026
One thing I’m wondering about is Redis server version compatibility. If native GCRA support is only available in newer Redis server versions, users running older Redis versions may not be able to use a Redis-backed GCRA limiter if the implementation depends only on the native command.
Would it make sense for the package/API to allow a Lua-script-based implementation as a compatibility path, at least until the native Redis command is broadly available? That could let the API stay aligned with a future native-command-based implementation while still supporting users on older Redis versions.
Yes, I’m specifically interested in GCRA for a multi-tenant SaaS scenario.
The main scenario is distributed rate limiting across multiple ASP.NET Core instances, where limits are partitioned by tenant and all instances need to share limiter state through Redis. The same mechanism could also apply to user-, client-, IP-, or endpoint-level limits depending on how the partition key is chosen.
GCRA is interesting here because it provides smoother request pacing than fixed-window counters, supports controlled bursts, requires only small per-partition state in Redis, and can provide a meaningful retry-after value when a request is throttled.
That said, I’m not trying to make the package GCRA-only. I agree that the package/API should be generic enough to support multiple Redis-backed rate limiting algorithms over time.
Thanks for taking a look and for the guidance.
DeagleGross commentedon Jul 8, 2026
Thanks @lqlive!
Agree. It's the decision we can make altogether - either we support the same algorithm "from scratch" (e.g. similar to your LUA scripting), or we throw if Redis does not support it via official built-in API. We have a precedent -
RedisOutputCacheStoretoday checks the version and then calls the API or invokes the script:aspnetcore/src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheStore.cs
Lines 281 to 298 in fbec0e6
So probably LUA-script-based implementation makes sense.
Totally, I agree that GCRA is a popular algorithm lately due to its usage convenience. I think if you can write up an API proposal - that would be a great next step.
To be on same page: this effort might not make into net11 due to we are in preview-6 already.
lqlive commentedon Jul 10, 2026
DeagleGross commentedon Jul 15, 2026
@lqlive thanks for working on this, and sending the code - I think what we need now is only the API proposal - specifically what new Public API we want to expose, and why (without inner implementation).
See examples:
Our process involves firstly looking into what new API should and should not exist (only signatures), and only then we can start with the actual PR review. But you can always attach the draft PR with the prototype to show how the API works under the hood (which is cheaper now due to AI).
lqlive commentedon Jul 15, 2026
@DeagleGross got it, my misunderstanding. I'll have the API proposal ready this week. Thanks!