Skip to content

docs: add sliding window rate limiter example notebook - #4248

Open
YashwinReddy29 wants to merge 1 commit into
redis:masterfrom
YashwinReddy29:docs/sliding-window-rate-limiter
Open

docs: add sliding window rate limiter example notebook#4248
YashwinReddy29 wants to merge 1 commit into
redis:masterfrom
YashwinReddy29:docs/sliding-window-rate-limiter

Conversation

@YashwinReddy29

@YashwinReddy29 YashwinReddy29 commented Aug 5, 2026

Copy link
Copy Markdown

What this adds

A new Jupyter notebook docs/examples/rate_limiter_sliding_window.ipynb
showing two sliding window rate limiter implementations using Redis:

  • Sorted set approach using ZADD and ZREMRANGEBYSCORE
  • Atomic Lua script version that eliminates race conditions in
    multi-instance deployments
  • Async version using redis.asyncio

Why it's useful

The existing examples cover data structures, search, pipelines, and
connections. There is no example showing rate limiting — a very common
Redis use case. The sliding window pattern is more accurate than fixed
window and is the pattern most teams reach for in production.

Context

Built this pattern in production for a distributed rate limiting
microservice handling high-throughput concurrent traffic.


Note

Low Risk
Documentation-only addition; no runtime, library, or production code paths change.

Overview
Adds docs/examples/rate_limiter_sliding_window.ipynb, a new documentation example for sliding-window rate limiting with Redis.

The notebook walks through a sorted-set limiter (ZREMRANGEBYSCORE / ZCARD / ZADD with key TTL), an atomic Lua variant via register_script for multi-instance safety, and an redis.asyncio pipeline version. Each section includes a small demo (e.g. 5 requests per 10 seconds) and documents expected allow/reject output.

Reviewed by Cursor Bugbot for commit af4f39e. Bugbot is set up for automated code reviews on this repo. Configure here.

Signed-off-by: Yashwin Reddy Lakkireddy <yashwinlakkireddy@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af4f39ecf1

ℹ️ 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".

" limit: int,\n",
" window_seconds: int,\n",
") -> bool:\n",
" result = sliding_window(\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Execute the script on the supplied client

When this helper is copied and called with any client other than the global r used during setup (for example a different DB, host, cluster client, or test fixture), this call still runs the registered script against r, so the passed client argument is ignored and the rate-limit key is checked/mutated on the wrong connection. Pass client=client to the Script call or register the script on the provided client.

Useful? React with 👍 / 👎.

" await async_client.aclose()\n",
"\n",
"\n",
"asyncio.run(main())"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use top-level await in the notebook

Because this code lives in a Jupyter notebook, this cell runs inside an IPython event loop; asyncio.run(main()) raises RuntimeError in that environment instead of executing the async example. The existing async notebook examples use top-level await, so this should end with await main() to keep the notebook runnable.

Useful? React with 👍 / 👎.

Comment on lines +211 to +214
" _, count = await pipe.execute()\n",
"\n",
" if count < limit:\n",
" await client.zadd(key, {str(uuid.uuid4()): now})\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the async limiter atomic under concurrency

For async apps with concurrent workers, this repeats the non-atomic check-then-add pattern after the notebook has introduced the Lua script as the concurrency-safe implementation: two callers can both observe count < limit here and then both add, exceeding the configured limit. Either show an async version of the Lua script or explicitly mark this async helper as having the same race as the first sorted-set example.

Useful? React with 👍 / 👎.

"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prevent docs from auto-executing the notebook

Because every code cell is committed without stored outputs and docs/conf.py does not override nbsphinx_execute, nbsphinx's default auto mode executes the notebook during the Sphinx build; the later example cells call r.delete(...) against localhost:6379, so invoke build-docs fails anywhere Redis is not already running. Store executed outputs or set notebook metadata to skip execution.

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit af4f39e. Configure here.

" keys=[key],\n",
" args=[time.time(), window_seconds, limit, str(uuid.uuid4())],\n",
" )\n",
" return bool(result)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignored Redis client parameter

Medium Severity

The is_allowed_atomic function accepts a client argument, but the registered sliding_window script isn't executed with it. This causes the rate limit logic to always run on the client used during script registration, potentially leading to operations on an unintended Redis connection or database.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit af4f39e. Configure here.

" await async_client.aclose()\n",
"\n",
"\n",
"asyncio.run(main())"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asyncio.run breaks notebook cell

Medium Severity

The async example's use of asyncio.run(main()) causes a RuntimeError in Jupyter/IPython environments because an event loop is already active. This prevents the async demonstration from running as intended.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit af4f39e. Configure here.

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