* CSC POC ontop of Parser * add csc file that weren't merged after patch * address review comments * nits to try and fix github * last change from review * Update client-side cache and improve documentation * Add client side caching RESP3 validation * Add documentation for RESP and unstableResp3 options * Add comprehensive cache statistics The `CacheStats` class provides detailed metrics like hit/miss counts, load success/failure counts, total load time, and eviction counts. It also offers derived metrics such as hit/miss rates, load failure rate, and average load penalty. The design is inspired by Caffeine. `BasicClientSideCache` now uses a `StatsCounter` to accumulate these statistics, exposed via a new `stats()` method. The previous `cacheHits()` and `cacheMisses()` methods have been removed. A `recordStats` option (default: true) in `ClientSideCacheConfig` allows disabling statistics collection. --------- Co-authored-by: Shaya Potter <shaya@redislabs.com>
5.1 KiB
RESP3 Support
Node Redis v5 adds support for RESP3, the new Redis serialization protocol. RESP3 offers richer data types and improved type handling compared to RESP2.
To use RESP3, specify it when creating your client:
import { createClient } from 'redis';
const client = createClient({
RESP: 3
});
Type Mapping
With RESP3, you can leverage the protocol's richer type system. You can customize how different Redis types are represented in JavaScript using type mapping:
import { createClient, RESP_TYPES } from 'redis';
// By default
await client.hGetAll('key'); // Record<string, string>
// Use Map instead of plain object
await client.withTypeMapping({
[RESP_TYPES.MAP]: Map
}).hGetAll('key'); // Map<string, string>
// Use both Map and Buffer
await client.withTypeMapping({
[RESP_TYPES.MAP]: Map,
[RESP_TYPES.BLOB_STRING]: Buffer
}).hGetAll('key'); // Map<string, Buffer>
This replaces the previous approach of using commandOptions({ returnBuffers: true })
in v4.
PubSub in RESP3
RESP3 uses a different mechanism for handling Pub/Sub messages. Instead of modifying the onReply
handler as in RESP2, RESP3 provides a dedicated onPush
handler. When using RESP3, the client automatically uses this more efficient push notification system.
Known Limitations
Unstable Module Commands
Some Redis module commands have unstable RESP3 transformations. These commands will throw an error when used with RESP3 unless you explicitly opt in to using them by setting unstableResp3: true
in your client configuration:
const client = createClient({
RESP: 3,
unstableResp3: true
});
The following commands have unstable RESP3 implementations:
-
Stream Commands:
XREAD
andXREADGROUP
- The response format differs between RESP2 and RESP3
-
Search Commands (RediSearch):
FT.AGGREGATE
FT.AGGREGATE_WITHCURSOR
FT.CURSOR_READ
FT.INFO
FT.PROFILE_AGGREGATE
FT.PROFILE_SEARCH
FT.SEARCH
FT.SEARCH_NOCONTENT
FT.SPELLCHECK
-
Time Series Commands:
TS.INFO
TS.INFO_DEBUG
If you need to use these commands with RESP3, be aware that the response format might change in future versions.
Sentinel Support
multi.exec<'typed'>
/ multi.execTyped
We have introduced the ability to perform a "typed" MULTI
/EXEC
transaction. Rather than returning Array<ReplyUnion>
, a transaction invoked with .exec<'typed'>
will return types appropriate to the commands in the transaction where possible:
const multi = client.multi().ping();
await multi.exec(); // Array<ReplyUnion>
await multi.exec<'typed'>(); // [string]
await multi.execTyped(); // [string]
Client Side Caching
Node Redis v5 adds support for Client Side Caching, which enables clients to cache query results locally. The server will notify the client when cached results are no longer valid.
Client Side Caching is only supported with RESP3.
Usage
There are two ways to implement client side caching:
Anonymous Cache
const client = createClient({
RESP: 3,
clientSideCache: {
ttl: 0, // Time-to-live in milliseconds (0 = no expiration)
maxEntries: 0, // Maximum entries to store (0 = unlimited)
evictPolicy: "LRU" // Eviction policy: "LRU" or "FIFO"
}
});
In this instance, the cache is managed internally by the client.
Controllable Cache
import { BasicClientSideCache } from 'redis';
const cache = new BasicClientSideCache({
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
});
const client = createClient({
RESP: 3,
clientSideCache: cache
});
With this approach, you have direct access to the cache object for more control:
// Manually invalidate keys
cache.invalidate(key);
// Clear the entire cache
cache.clear();
// Get cache metrics
// `cache.stats()` returns a `CacheStats` object with comprehensive statistics.
const statistics = cache.stats();
// Key metrics:
const hits = statistics.hitCount; // Number of cache hits
const misses = statistics.missCount; // Number of cache misses
const hitRate = statistics.hitRate(); // Cache hit rate (0.0 to 1.0)
// Many other metrics are available on the `statistics` object, e.g.:
// statistics.missRate(), statistics.loadSuccessCount,
// statistics.averageLoadPenalty(), statistics.requestCount()
Pooled Caching
Client side caching also works with client pools. For pooled clients, the cache is shared across all clients in the pool:
const client = createClientPool({RESP: 3}, {
clientSideCache: {
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
},
minimum: 5
});
For a controllable pooled cache:
import { BasicPooledClientSideCache } from 'redis';
const cache = new BasicPooledClientSideCache({
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
});
const client = createClientPool({RESP: 3}, {
clientSideCache: cache,
minimum: 5
});