DOC-6999: port alternative rate limiter algorithms to the other eight client pages - #3861
Merged
Merged
Conversation
Adds fixed window counter, sliding window log, sliding window counter and leaky bucket to the dotnet, go, java-jedis, java-lettuce, nodejs, php, ruby and rust rate limiter pages, following the community contribution in #3788 that added them to redis-py only. Lettuce gets sync only, matching its existing token bucket examples, and everything is snippets — no new runnable source files, so these four algorithms stay unbacked by demo code the way redis-py left them. The four Lua scripts are the algorithm; only the wrapper is per-language. So the sections were generated from a script that extracts the Lua and the prose once from redis-py and reuses both, rather than being written eight times by hand. That is the only reason nine copies can be trusted to stay in step, and it is why the identity check below is worth re-running after any edit here. Two things that cost time and will cost it again. First, the obvious way to extract the Lua back out for comparison — take lines from the first "local" to the last "return {" — silently over-captures, because the wrapper code also contains a return of a brace-delimited value. It reported four false mismatches before the bound was changed to the host string-literal terminator. Second, compiling the dotnet snippets reported Guid as unresolved, which looks like a defect in the snippet but is the harness missing ImplicitUsings; these pages already assume it, since the existing examples call Console.WriteLine with no System import. A check project has to match what "dotnet new console" gives the reader or it manufactures errors. Also corrects a claim on the redis-py page before copying it eight times over: it said all four algorithms read the server clock via TIME, but the fixed window counter reads no clock at all and leans on the key's TTL. Verified by compiling against jedis 7.5.3, lettuce-core 7.7.0, StackExchange.Redis 2.9.32 and redis 0.24.1, parsing the rest, running the four scripts and the full Ruby wrappers against a live server, and a clean Hugo build with every comparison-table anchor resolving. Learned: an extractor bounded by a code pattern the wrapper also contains over-captures, and a compile harness that misses the reader's project defaults invents failures Constraint: the four Lua scripts must stay byte-identical across all nine rate-limiter pages — that is what makes the reuse safe Directive: never hand-edit the Lua on one page; change all nine together and re-run the identity check bounded by the string-literal terminator, not by "return {" Rejected: uuid-free sorted-set members for rust from pid plus a counter | pid collisions across hosts silently overwrite log entries and undercount, so the uuid crate is worth the dependency Rejected: inserting the section after Response headers to mirror redis-py's offset | splits the token bucket material, because each page's Customization section refers back to the token bucket limiter Gaps: only the Ruby wrappers were run end to end; the other seven were compiled or parsed, so per-language argument marshalling and return unpacking are unproven Ticket: DOC-6999 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Contributor
Contributor
…-py page Every other rate limiter client page explains that the limiter caches its script and sends EVALSHA, and every one tells you how to install the client. The redis-py page did neither, even though its own token_bucket.py has done the SHA1-plus-script-load-plus-fallback dance since it was written. This adds both sections in the position the eight sibling pages use. The wire behaviour in the new section was traced with MONITOR rather than read off the source. TokenBucket sends SCRIPT LOAD on the first allow and EVALSHA after that, as expected. The part worth writing down is the alternative algorithm snippets, which call register_script on every request and look wasteful: they are not, because redis-py derives the digest from the script text client-side, so a freshly built Script object has the same digest and EVALSHA still hits the cached script. Three calls through a per-request register_script produced three EVALSHA commands and no extra round trip. Installation stays shorter than the ruby and rust equivalents on purpose, since naming a minimum redis-py version would have meant inventing one. Learned: redis-py computes the EVALSHA digest client-side from the script text, so re-registering a Script per call costs nothing on the wire — MONITOR-verified, not inferred Rejected: pinning a version floor in the Installation section the way the ruby and rust pages pin theirs | the floor was never verified and a wrong minimum misleads more than an absent one Ticket: DOC-6999 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dwdougherty
approved these changes
Aug 26, 2026
dwdougherty
left a comment
Collaborator
There was a problem hiding this comment.
Language LGTM. I did not scrutinize the code.
Contributor
Author
|
Thanks @dwdougherty ! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3788, which added four extra rate limiting algorithms to the redis-py page only. This ports them to the remaining eight client pages. DOC-6999
What this adds
The
Alternative rate limiting algorithmssection — comparison table plus fixed window counter, sliding window log, sliding window counter, and leaky bucket (policing) — on dotnet, go, java-jedis, java-lettuce, nodejs, php, ruby, and rust.Eight pages, not the six named in #3788:
javais two separate pages (Jedis and Lettuce), andrubywas omitted from that list.Approach
The four Lua scripts are the algorithm, so they are reused byte-for-byte — only the wrapper around each script is per-language. The sections were generated from a script that extracts the Lua and the language-agnostic prose once from the redis-py page, rather than being written out eight times by hand.
Verified after the fact by extracting all 36 script instances (9 pages x 4 scripts) back out of the written files and diffing them against the originals: byte-identical once the host string literal's indentation is stripped.
Two judgment calls
token_bucket.py,TokenBucket.cs, and so on). These four algorithms are snippets, exactly as redis-py left them. Adding 32 runnable demos would be a much larger job and belongs in its own ticket.Placement
The section sits immediately before
## Learn more, i.e. after## Customization. On redis-py those are the same position (it has no Customization section). Mirroring redis-py's literal offset — straight after## Response headers— would have split the token bucket material on the other eight, because each page's Customization section refers back to the token bucket limiter.One correction to the merged redis-py page
The section intro claimed all four algorithms derive the timestamp from the server clock via
redis.call('TIME'). Three do; the fixed window counter reads no clock at all and leans on the key's TTL. Reworded on all nine pages rather than copied eight more times.Verification
gofmt -e(clean, no formatting diff),node --check,ruby -c,php -l.{rswc}:178767316, confirming the hash-tag marshalling yields the Cluster-safe key the prose describes.Not verified: the seven non-Ruby wrappers were compiled or parsed, not executed. The Lua they call is proven identical and run-tested, so algorithm behavior is covered; what is untested per language is argument marshalling and return unpacking.
Also brings redis-py into line with its siblings
The redis-py page was missing two sections that all eight other client pages have:
## Installationand### Script caching with EVALSHA. Both are now added in the sibling position, since this PR is effectively a general pass over the rate limiter use case.The EVALSHA section's claims were traced with
MONITORrather than read off the source.TokenBucketsendsSCRIPT LOADon the firstallow()andEVALSHAthereafter. The non-obvious part: the four alternative-algorithm snippets callregister_script()on every request, which looks wasteful but is not — redis-py derives the digest from the script text client-side, so a freshly builtScriptobject has the same digest andEVALSHAstill hits the cached script. Three calls through a per-requestregister_script()produced threeEVALSHAcommands and no extra round trip.Installation is deliberately shorter than the ruby and rust equivalents: naming a minimum redis-py version would have meant inventing one.
🤖 Generated with Claude Code
Note
Low Risk
Documentation-only changes to Hugo markdown; no runtime or security-sensitive code paths.
Overview
Ports the Alternative rate limiting algorithms content from the redis-py guide to dotnet, go, java-jedis, java-lettuce, nodejs, php, ruby, and rust. Each page gets the same comparison table, shared prose, and four byte-identical Lua scripts with per-language
EVALwrappers (fixed window, sliding window log, sliding window counter with{key}hash tags, leaky bucket policing).Sections are inserted immediately before
## Learn moreso they stay after customization/error-handling material. Lettuce examples use syncRedisCommandsonly, matching how those pages present token bucket.On redis-py, adds missing
## Installationand### Script caching with EVALSHA(including howregister_script()still hitsEVALSHA), and corrects the section intro on all nine pages: only three algorithms useredis.call('TIME'); the fixed window counter relies on key TTL, not the server clock.Reviewed by Cursor Bugbot for commit ec63c7c. Bugbot is set up for automated code reviews on this repo. Configure here.