Repository navigation
examples: add fixed-window rate-limiter using INCR and EXPIRE - #3453
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4090d3595f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
nkaradzhov
left a comment
There was a problem hiding this comment.
Thanks for the contribution — a rate-limiter recipe is a great fit for examples.
One correctness issue before we can merge:
The INCR / conditional EXPIRE pair has a leak race. If the process crashes between the INCR and the EXPIRE, the key is created with no TTL. Because the key name embeds the window stamp, it will never be written again — so it stays in Redis forever. This is the exact race the Redis docs warn about (https://redis.io/docs/latest/commands/incr/#pattern-rate-limiter-2) in this pattern.
Since your key is already scoped to the window, the fix is to drop the if (currentCount === 1) check and always send both commands atomically:
const [currentCount] = await client.multi()
.incr(rateLimitKey)
.expire(rateLimitKey, WINDOW_SIZE_IN_SECONDS)
.exec();
Re-running EXPIRE on every request is harmless here (the window stamp in the key does the real reset), and this also saves a round trip. Alternatively, on Redis ≥ 7 you can keep the two calls and use client.expire(rateLimitKey, WINDOW_SIZE_IN_SECONDS, 'NX').
Two small things:
- client.quit() is deprecated in v5 — use client.close() (or client.destroy(), as the other examples do).
- Could you add a link to the rate-limiter pattern on the INCR page (https://redis.io/docs/latest/commands/incr/#pattern-rate-limiter) in the header comment? We'd like the examples to show the idiomatic node-redis code and point to redis.io for the algorithm discussion.
Also, please fill in the PR description. Thanks again!

Description
Adds a practical example recipe demonstrating a fixed-window rate limiter using Redis
INCRandEXPIRE.client.multi()transaction (INCR+EXPIRE) to prevent the key leak race condition if a process crashes between commands.client.close()for proper client lifecycle management.examples/README.mdindex table with the new recipe.Checklist
npm testpass with this change (including linting)?