You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Remote invalidation is scalar at both the public API and semantic Redis boundary. Applications invalidating many independent identities therefore make one semantic call and normally one client/script submission per identity.
Core submits one semantic adapter call when the capability exists. Existing custom DialCacheRedisClient implementations remain compatible through an all-settled scalar invalidate() fallback that launches every target concurrently; custom adapters own any additional dispatch limits. Cluster topology, slot calculation, native batch APIs, chunking, and client-specific errors stay inside adapters.
Standalone and Cluster execution
A literal Redis MULTI/EXEC cannot cover arbitrary Cluster slots. Every tracked (namespace, keyType, id) receives its own hash tag so the value and watermark colocate, while different identities normally occupy different slots. Each bundled adapter therefore uses a non-atomic chunking strategy.
node-redis 4.7
Use a private fixed ceiling of 1,000 invalidation commands per execution chunk; no public setting is added.
Calculate each watermark key slot with a private Redis-spec CRC16/XMODEM helper.
Snapshot the current node-redis slot table and group mapped requests by slots[slot].master.id.
Run targeted primary-owner groups concurrently and each owner's first-key-routed pipeline chunks sequentially. node-redis remains responsible for selecting the node connection.
The Cluster pipeline count is sum(ceil(ownerTargets / 1,000)); it equals the number of targeted primaries when every owner has at most 1,000 targets.
Route unmapped slots through registered scalar scripts in sequential windows of at most 1,000 concurrent calls rather than isolated one-command pipelines.
If an owner chunk ultimately fails with a direct MOVED or ASK, retry only that chunk through independently routed scalar commands. Preserve all non-redirection errors unchanged.
Scalar recovery starts only after node-redis exhausts its configured maxCommandRedirections budget, 16 retries by default.
If a narrow structural wrapper has no multi, use the bounded scalar compatibility path.
The ceiling bounds DialCache's queued contribution per chunk, but cannot guarantee admission with a lower or already-occupied caller commandsQueueMaxLength.
Retain the standalone pipeline for bounded dispatch, reply-count validation, and efficient cold-script recovery. Warm concurrent scalar calls are already auto-pipelined, so this is not a general steady-state throughput claim.
Valkey GLIDE
Apply a private fixed ceiling of 1,000 commands to native Batch(false) / ClusterBatch(false) dispatch and scalar-only compatibility wrappers.
Submit native chunks sequentially and let GLIDE route each non-atomic Cluster chunk across its target nodes.
Submit scalar-wrapper calls in sequential windows of at most 1,000 concurrent invocations and settle every launched call in a window.
Use EVALSHA when the script handle exposes getHash().
After a confirmed script-cache miss, retry only the affected idempotent chunk once with EVAL; unrelated errors are unchanged.
Enable documented retriable server/connection behavior only on the detected native Cluster path.
A failed native chunk or scalar window prevents later chunks from starting.
Retain scalar fallback for narrow wrappers without native batch capabilities.
The ceiling bounds DialCache's contribution but cannot guarantee scalar-path admission against a lower or already-occupied GLIDE in-flight request limit.
Treat the observed GLIDE 2.4.2 script-miss message as an intentional version-coupled matcher and fail closed on unrelated formats.
No public Cluster abstraction, topology option, new slot dependency, or public pipeline-size configuration is introduced.
Failure and observability semantics
Derive all watermark requests before Redis dispatch.
Emit one invalidation metric per attempted unique canonical target.
On failure, log once and emit one bounded error per distinct targeted key type.
Start independent node-redis primary-owner and unmapped-scalar groups concurrently.
Process bundled-adapter chunks within one execution group sequentially. A failed chunk prevents later chunks in that group from being submitted, while every already-started node-redis group settles before rejection.
Settle every launched scalar call in core's custom-adapter fallback and GLIDE's current scalar window.
Preserve one failure identity; aggregate multiple failures deterministically.
Cross-primary, native-batch, and scalar-window execution can completely, partially, or ambiguously apply before rejection. There is no rollback.
Retrying the canonical target list is safe because each script advances its watermark monotonically.
Acceptance criteria
Add the typed batch API while retaining scalar invalidateRemote.
Preserve the scalar watermark protocol and key format.
Use an optional semantic adapter batch capability with scalar custom-adapter fallback.
Bound node-redis pipeline and scalar execution chunks to 1,000 commands.
Bound GLIDE native batches and scalar-wrapper windows to 1,000 commands.
Keep topology and chunking logic inside adapters.
Group node-redis Cluster requests by targeted current primary and retain client-selected routing.
Run primary-owner groups concurrently and chunks within an owner sequentially.
Recover stale-topology MOVED/ASK failures through bounded per-key routing.
Use registered scalar routing for unmapped Cluster slots.
Use GLIDE native cross-slot batching with per-chunk warm EVALSHA and cold EVAL recovery.
Verify slot calculation against live CLUSTER KEYSLOT, including hash tags and UTF-8.
449 unit tests passed with 97.17% statement coverage.
Build, declarations, and packed-consumer tests passed.
99 live integration tests passed across Redis 6.2, Valkey 8, node-redis, GLIDE, and a three-primary Redis 7 Cluster.
Repeated node-redis and Valkey GLIDE standalone benchmark watermark assertions passed for 10, 100, and 1,000 targets; timings remain directional and carry no threshold.
Priority
P3 — Low — later or demand-driven enhancement.
Problem
Remote invalidation is scalar at both the public API and semantic Redis boundary. Applications invalidating many independent identities therefore make one semantic call and normally one client/script submission per identity.
Implementation is in #114.
Confirmed API
{ keyType, id }pairs, not parallel arrays or a cross product.futureBufferMsapplies to the batch.String(id)and duplicate canonical pairs collapse in first-occurrence order.invalidateRemoteAPI, watermark protocol, key format, remote-only behavior, and application-owned future-buffer contract remain unchanged.Semantic Redis boundary
The semantic client gains an optional capability:
Core submits one semantic adapter call when the capability exists. Existing custom
DialCacheRedisClientimplementations remain compatible through an all-settled scalarinvalidate()fallback that launches every target concurrently; custom adapters own any additional dispatch limits. Cluster topology, slot calculation, native batch APIs, chunking, and client-specific errors stay inside adapters.Standalone and Cluster execution
A literal Redis
MULTI/EXECcannot cover arbitrary Cluster slots. Every tracked(namespace, keyType, id)receives its own hash tag so the value and watermark colocate, while different identities normally occupy different slots. Each bundled adapter therefore uses a non-atomic chunking strategy.node-redis 4.7
ceil(targets / 1,000)sequential pipelines.slots[slot].master.id.sum(ceil(ownerTargets / 1,000)); it equals the number of targeted primaries when every owner has at most 1,000 targets.MOVEDorASK, retry only that chunk through independently routed scalar commands. Preserve all non-redirection errors unchanged.maxCommandRedirectionsbudget, 16 retries by default.multi, use the bounded scalar compatibility path.commandsQueueMaxLength.Valkey GLIDE
Batch(false)/ClusterBatch(false)dispatch and scalar-only compatibility wrappers.EVALSHAwhen the script handle exposesgetHash().EVAL; unrelated errors are unchanged.No public Cluster abstraction, topology option, new slot dependency, or public pipeline-size configuration is introduced.
Failure and observability semantics
Acceptance criteria
invalidateRemote.MOVED/ASKfailures through bounded per-key routing.EVALSHAand coldEVALrecovery.CLUSTER KEYSLOT, including hash tags and UTF-8.CROSSSLOTerrors.Out of scope
Validation snapshot
At PR head
c8869e4on Node.js 22.22.0:Related work