Skip to content

Implement ConcurrencyLimitRateLimiter strategy#363

Open
dimartiro wants to merge 2 commits into
alisaifee:masterfrom
dimartiro:revive/concurrency-limiter
Open

Implement ConcurrencyLimitRateLimiter strategy#363
dimartiro wants to merge 2 commits into
alisaifee:masterfrom
dimartiro:revive/concurrency-limiter

Conversation

@dimartiro

Copy link
Copy Markdown

This revives #233, which was approved by reviewers but closed for inactivity after a request to add tests. The original branch was ~2 years (307 commits) behind master, so this reintroduces the strategy on top of the current storage API and addresses the test request.

What this adds

  • ConcurrencyLimitRateLimiter (sync limits.strategies + async limits.aio.strategies), registered as the concurrency-limit strategy. Unlike the window-based strategies it bounds in-flight concurrency: hit() acquires slots and release() hands them back. A safety expiry (derived from the limit period) reclaims slots leaked by callers that never release.
  • ConcurrencyLimitSupport capability mixin (sync + async) exposing decr, mirroring the existing MovingWindowSupport / SlidingWindowCounterSupport pattern. The in-memory storage (which already implements decr) opts in; the limiter raises NotImplementedError for storages that don't support it.
  • Tests (the change requested on Implement ConcurrencyLimitRateLimiter strategy #233): sync + async suites covering acquire/release, multi-cost, rejection-without-consumption, release flooring at zero, and clear.
  • Docs: README, strategies guide, and API reference.

Notes

  • hit() uses acquire-then-rollback (incr, then decr on overflow) so the counter stays accurate under contention and rejected hits never consume a slot — an improvement over the original get-then-incr which had a race.
  • decr currently only exists on the in-memory storage, so the strategy is wired for in-memory here; extending decr to the redis / memcached / mongodb backends to broaden support can follow.

Supersedes #233.

Reintroduces the concurrency limit strategy on top of the current storage
API. Unlike the window based strategies it bounds the number of in-flight
requests: `hit` acquires slots and `release` hands them back, with a safety
expiry so leaked slots are eventually reclaimed.

- Add `ConcurrencyLimitSupport` capability mixin (sync + async) exposing
  `decr`; wire it into the in-memory storage which already implements it.
- Implement `ConcurrencyLimitRateLimiter` for both `limits.strategies` and
  `limits.aio.strategies`, registered as the `concurrency-limit` strategy.
  The limiter requires a storage supporting `decr` and raises
  `NotImplementedError` otherwise (mirrors the moving/sliding window checks).
- Acquire-then-rollback in `hit` keeps the counter accurate under contention
  and never counts rejected hits.
- Add sync + async test suites exercising acquire/release, multi-cost,
  rejection without consumption, release flooring at zero, and clear.
- Document the strategy in the README, strategies guide and API reference.
@dimartiro dimartiro force-pushed the revive/concurrency-limiter branch from 004d0fd to cbffd62 Compare July 2, 2026 12:49
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.

1 participant