Skip to content

test(redis): lock in cluster-safe single-key invariant#49

Merged
mrjasonroy merged 1 commit into
mainfrom
test/cluster-safe-single-key
Jun 25, 2026
Merged

test(redis): lock in cluster-safe single-key invariant#49
mrjasonroy merged 1 commit into
mainfrom
test/cluster-safe-single-key

Conversation

@mrjasonroy

Copy link
Copy Markdown
Owner

Why

The data-cache handler is compatible with Redis Cluster / ElastiCache (cluster-mode enabled) purely because it only ever issues single-key commands — Redis rejects any command spanning more than one hash slot with CROSSSLOT. That's an invariant worth guarding.

What

  • Test (redis.test.ts → "only ever issues single-key commands"): records every command the handler issues across its full surface — including both the tag-driven and TTL-driven deletion paths — and asserts none targets >1 key. Non-vacuous: it also asserts the del paths actually executed, so it fails loudly the day someone adds a del(k1, k2) / mget / multi-key transaction.
  • Docs (docs/redis.md): document the slot-safety guarantee, and clarify cluster-mode-disabled (single-node-equivalent) vs cluster-mode-enabled (ioredis Cluster client) ElastiCache.

Why not a live cluster CI job

Considered it, decided against:

  • A live cluster mostly exercises ioredis's redirect handling, not this library.
  • Redis Cluster in CI is a well-known flake source — as a required check it could wedge the hands-off auto-merge release gate we just built.
  • The thing that actually matters — the single-key invariant — is guarded here for free, with zero infra.

🤖 Generated with Claude Code

What keeps the data-cache handler compatible with Redis Cluster / ElastiCache
(cluster-mode enabled) is that it only ever issues single-key commands — Redis
rejects any command spanning >1 hash slot with CROSSSLOT. Add a test that
records every command across the full handler surface (both the tag-driven and
TTL-driven deletion paths) and asserts none targets more than one key, so a
future multi-key change (e.g. del(k1, k2), mget) can't silently break cluster
users. The test is non-vacuous — it asserts the del paths actually ran.

Also document the guarantee in docs/redis.md and clarify cluster-mode-disabled
vs -enabled ElastiCache (the former is single-node-equivalent; the latter uses
the ioredis Cluster client — slot-safe either way).

No live multi-node cluster CI: it would mostly exercise ioredis (not this
library), is a known source of CI flake, and would risk wedging the auto-merge
release gate for coverage a unit-tested invariant provides for free.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrjasonroy mrjasonroy enabled auto-merge (squash) June 25, 2026 23:04

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request adds documentation and a test suite to ensure and explain Redis Cluster safety, verifying that the handler only issues single-key commands to prevent CROSSSLOT errors. The feedback suggests making the new test more robust by asserting the exact keys that are deleted rather than just checking if any deletion occurred.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +427 to +428
// Both deletion paths must have run (otherwise the assertion is vacuous)...
expect(commands.some((c) => c.method === "del")).toBe(true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While asserting that del was called is a good sanity check, we can make this test significantly more robust and precise by asserting the exact keys that were deleted (nextjs:data-cache:k1 and nextjs:data-cache:k2). This ensures that the correct keys are targeted for deletion and prevents false positives where del might be called with unexpected keys.

    // Both deletion paths must have run (otherwise the assertion is vacuous)...
    const delCommands = commands.filter((c) => c.method === "del");
    expect(delCommands).toEqual([
      { method: "del", keys: ["nextjs:data-cache:k1"] },
      { method: "del", keys: ["nextjs:data-cache:k2"] }
    ]);

@mrjasonroy mrjasonroy merged commit f06b622 into main Jun 25, 2026
7 checks passed
@mrjasonroy mrjasonroy deleted the test/cluster-safe-single-key branch June 25, 2026 23:15
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