feat: add key prefixing (fixes #2982)#3312
Conversation
|
Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset. In case there are security findings, they will be communicated to you as a comment inside the PR. Hope you’ll enjoy using Jit. Questions? Comments? Want to learn more? Get in touch with us. |
|
Would appreciate guidance @nkaradzhov on the next steps |
|
@gajus i will try to review soon, as far as I remember though, there were some complications of having this, besides, there is a fairly simple workaround? Anyway, I will need to thoroughly look at this |
I am not aware of any simple workarounds. |
nkaradzhov
left a comment
There was a problem hiding this comment.
- WATCH doesn't get the prefix
WATCH builds its request differently from normal commands and skips prefixing. So it watches the unprefixed key while the commands inside the transaction use the prefixed key — it guards a key nobody writes to, and optimistic locking silently breaks with no error. Same through Sentinel.
const client = createClient({ keyPrefix: 'app:' });
await client.watch('k'); // watches "k" (unprefixed)
const m = client.multi().get('k'); // operates on "app:k" (prefixed)
// concurrent writer changes "app:k" -> EXEC does NOT abort; WATCH guarded wrong key
await m.exec();- Cluster multi routes on the unprefixed key
An explicit routing key passed to cluster.multi(routing) isn't prefixed, but the commands inside are — so the cluster picks the node from the unprefixed key while the data lives elsewhere → MOVED/cross-slot. Only with a prefix + explicit routing key, small clean fix:
const cluster = createCluster({ rootNodes, keyPrefix: 'app:' });
const multi = cluster.multi('user'); // routing "user" -> slot from "user"
multi.set('user', '1'); // command key prefixed -> "app:user" (different slot)
await multi.exec(); // routed by slot('user') -> MOVED / CROSSSLOT|
@nkaradzhov resolved |
|
@PavelPashov can you please take a look as well please! |
|
@gajus Consider using |
PavelPashov
left a comment
There was a problem hiding this comment.
Please document this scanIterator gotcha explicitly: it yields already-prefixed keys, so passing them back to key-prefixing commands will prefix them again unless callers strip the prefix first.
|
Both done |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Reviewed by Cursor Bugbot for commit bef1784. Configure here.

Description
Restores key prefixing functionality.
The reasoning is described in #2982
Checklist
npm testpass with this change (including linting)?Note
Medium Risk
Prefixing touches almost all command construction and cluster/sentinel routing and WATCH behavior; incorrect edge cases could cause silent wrong-key access or broken optimistic locking, though coverage is broad.
Overview
Adds a
keyPrefixclient option that prepends a string orBufferto every key on the wire, with ioredis-style semantics: outbound keys are prefixed, replies are not stripped,SCAN/KEYSMATCHpatterns are not auto-prefixed, and Pub/Sub channels (including shardedSPUBLISH) stay unprefixed.Prefixing is wired through
BasicCommandParser(prefixKey/prefixKeys, optionalpushKey(..., applyPrefix=false)), and every command path that builds parsers now passes the configured prefix—standalone client, pool, cluster, sentinel, MULTI/pipelines, andWATCH(which previously could watch the wrong key). The pool keeps prefixing at the pool layer and clearskeyPrefixon pooled node clients to avoid double-prefixing; clustermulti(routingKey)prefixes the explicit routing key so slot selection matches prefixed command keys.Several commands were adjusted to use
pushKeywhere keys were previously pushed raw (APPEND,SORTSTORE,MIGRATE,CLUSTER KEYSLOT). Docs cover configuration, semantics, and thescanIterator+mGetdouble-prefix pitfall; integration tests cover transactions, scripts, WATCH, pool/cluster/sentinel, and parser unit tests.Reviewed by Cursor Bugbot for commit bef1784. Bugbot is set up for automated code reviews on this repo. Configure here.