Skip to content

feat(ratelimit): accept Redis cluster clients and restructure adapter docs - #2014

Merged
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/redis-limiter-cluster-compat-bb7717
Sep 12, 2026
Merged

feat(ratelimit): accept Redis cluster clients and restructure adapter docs#2014
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/redis-limiter-cluster-compat-bb7717

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 12, 2026

Copy link
Copy Markdown
Member

RedisRateLimiter now accepts a node-redis cluster client as well as a standalone one, so it can be used against Redis Cluster without a cast. The script already keys on a single key, so requests route to the owning shard unchanged. The rate limit docs page now leads with the adapter overview and gives each adapter its own section with a short description.

Docs

  • The adapter table sits in Basic Usage and links to each adapter section; Blocking Mode stays with it.
  • Adapters moves to the end with one subsection per adapter instead of tabs.

Testing

  • Cluster: against a local 3-master Redis 8 cluster with node-redis 6.2.1, sequential and concurrent keys land on every master, limits hold, and a master that lost its script cache recovers through the NOSCRIPT retry.
  • Standalone: the existing Redis suite passes; type check, lint, and the JSDoc backlink checker pass.

Caveats

  • node-redis 6.0.x and 6.1.x route SCRIPT LOAD to one random node, so first requests on other shards can hit NOSCRIPT until the retry has loaded the script there. Both are still inside the >=6.0.0 peer range.
  • On a cluster client, concurrent limit() calls before connect() can fail with "The client is offline" because isOpen flips before topology discovery completes. Connecting first avoids it, as the docs example does.

… docs

RedisRateLimiter now accepts a node-redis cluster client alongside the
standalone client. The Lua script keys on a single key, so EVALSHA routes to
the owning shard, and node-redis 6.2+ loads the script on every node.

The rate limit docs page now leads with the adapter table in Basic Usage,
keeps Blocking Mode with it, and moves Adapters to the end with one
subsection and a short description per adapter instead of tabs.
@pkg-pr-new

pkg-pr-new Bot commented Sep 12, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2014

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2014

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2014

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2014

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2014

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2014

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@2014

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2014

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2014

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2014

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@2014

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2014

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2014

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2014

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2014

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2014

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2014

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2014

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2014

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2014

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2014

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2014

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2014

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2014

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2014

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2014

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2014

commit: bc3e671

@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/redis-limiter-cluster-compat-bb7717 (bc3e671) with main (8b4ee55)

Open in CodSpeed

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ Minor suggestions only.

Reviewed changes

  • Redis cluster typingRedisRateLimiter's field and constructor parameter are widened from RedisClientType to RedisClientType | RedisClusterType; purely a type change with no runtime path touched. Both types expose isOpen/connect/scriptLoad/evalSha through the same mixin, so the union compiles (type:check and eslint pass locally).
  • Adapter docs restructure — Basic Usage now leads with an adapter table linking to per-adapter sections, ### Blocking Mode moves under Basic Usage, middleware/handler-plugin stay in the middle, and ## Adapters moves to the end with one subsection per adapter instead of tabbed <CodeGroup> fences. All anchors resolve and the 4-backtick Upstash fence is preserved.

The type change itself is sound — on node-redis 6.2 SCRIPT LOAD is fanned out to all masters, so the cached scriptSha and the NOSCRIPT reload-retry work on a cluster. The one concern is that the docs advertise cluster support without the version caveat noted in the PR description; details inline.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using openrouter/deepseek/deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

```ts redis
### Redis

Stores counters in Redis, so every instance using the same server enforces the same limits. Works with both standalone and cluster clients.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The cluster support claim here has two sharp edges the docs don't mention. On node-redis 6.0.x/6.1.x — still inside the >=6.0.0 peer range — SCRIPT LOAD isn't fanned out to every master, so the NOSCRIPT reload-retry can reload onto the wrong shard and still fail; and on a cluster, concurrent first limit() calls before connect() can fail with "The client is offline" because isOpen flips before topology discovery finishes (the example below calls connect() for this reason, but describes it as optional). Consider scoping the support claim or noting the minimum node-redis version.

Technical details
# Cluster support has undocumented caveats

## Affected sites
- `apps/content/docs/helpers/ratelimit.mdx:190` — claims "Works with both standalone and cluster clients" unconditionally
- `packages/ratelimit/src/adapters/redis.ts:123``executeScript` reload-retry depends on `SCRIPT LOAD` reaching the shard that owns the key
- `packages/ratelimit/package.json:69``"redis": ">=6.0.0"` admits versions with single-node `SCRIPT LOAD` routing

## Required outcome
- The documented cluster support is accurate across the allowed `redis` peer range, or the adapter is made shard-safe on 6.0.x/6.1.x.

## Suggested approach (optional)
- Add a short note that cluster use requires node-redis >= 6.2 (where `SCRIPT LOAD` fans out to all masters), or
- On `NOSCRIPT`, fall back to `EVAL` with the script body instead of re-running `scriptLoad` + `evalSha`: `EVAL` routes by the single key to the owning shard and loads the script there, sidestepping the per-node cache problem on every supported version.

## Open questions for the human
- Should clusters be supported across the whole `>=6.0.0` peer range, or is raising the peer floor to 6.2 acceptable?

@dinwwwh
dinwwwh merged commit 9c1a969 into middleapi:main Sep 12, 2026
11 checks passed
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