feat(rate-limit/unstable): add rate limiting module#7063
feat(rate-limit/unstable): add rate limiting module#7063tomas-zijdemans wants to merge 29 commits intodenoland:mainfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7063 +/- ##
==========================================
+ Coverage 94.61% 94.70% +0.09%
==========================================
Files 634 645 +11
Lines 51801 52826 +1025
Branches 9329 9475 +146
==========================================
+ Hits 49011 50031 +1020
Misses 2216 2216
- Partials 574 579 +5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
bartlomieju
left a comment
There was a problem hiding this comment.
This is a well-architected and thoroughly tested package. The layered design (pure algorithms → keyed wrapper → async queue/timer/disposal → public API) is clean, and the algorithm implementations look mathematically correct. Solid work.
A few things to address before merge:
Blockers:
- CI: PR title validation is failing —
rate-limitneeds to be added to the scopes list in.github/workflows/title.ymlin a preceding PR. - Discussion: Is there a tracking issue or RFC for adding a rate-limiting package to
@std? This is a significant addition (~5100 lines) and new packages typically need community buy-in. mod.ts: Ensure it has the@moduleJSDoc tag per repo conventions.
Design/correctness notes:
peek()in keyed algorithms mutates state:peek()callsops.advance(), which rotates segment counters in sliding-window. This means "peeking" isn't truly read-only — it advances time. This is necessary for correct metadata but should be documented explicitly.- Depends on unstable APIs: Imports
RollingCounterfrom@std/data-structures/unstable-rolling-counterand usesDeque. Fine for v0.1.0 but worth noting as a stability risk. - TokenBucket
result()usesthis.computeRetryAfter()rather than calling the method directly — minor style inconsistency with the other algorithm implementations which inline the computation. - Some JSDoc examples use
limiter[Symbol.dispose]()syntax — consider using theusingstatement for consistency with newer examples elsewhere. - Naming inconsistency:
TokenBucketOptionsusestokenLimit+tokensPerPeriod+replenishmentPeriod, whilecreateRateLimiteruseslimit+window+tokensPerCycle. The different naming across the same domain could be confusing. - Floating-point edge cases: TokenBucket uses fractional tokens internally (
Math.floor(state.tokens)for remaining). No tests specifically exercise floating-point boundary behavior (e.g., tokens at 4.999... after refill).
|
Thank you for the review. I pushed a new commit now:
Let me know if you agree/disagree or have any further feedback |
…7046) Sliding expiration: entries can now stay alive as long as they're being accessed, with an optional hard deadline. Useful for sessions or rate-limit windows.
|
Changed to use stable Deque |
New Rate limit module
This new module offers strategies for controlling how many operations can occur over time.
The primary API is
createRateLimiter, a keyed rate limiter for the common case of "allow key X at most N requests per window." It supports fixed-window, sliding-window, token-bucket, and GCRA algorithms.For single-resource limiting, use the primitives:
createTokenBucket,createFixedWindow, andcreateSlidingWindow.The rate limiter supports both in-memory usage and Redis-backed storage for distributed rate limiting across multiple processes or deployments.
Depends on
@std/data-structures:Dequefor async queue management andRollingCounterfor sliding-window segment tracking.Planned future additions