Skip to content

Commit 3dd810b

Browse files
committed
docs: RESP3 and client-side caching documentation
1 parent 286b6ef commit 3dd810b

File tree

4 files changed

+187
-13
lines changed

4 files changed

+187
-13
lines changed

docs/v4-to-v5.md

+2
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ In v5, any unwritten commands (in the same pipeline) will be discarded.
225225

226226
- `FT.SUGDEL`: [^boolean-to-number]
227227
- `FT.CURSOR READ`: `cursor` type changed from `number` to `string` (in and out) to avoid issues when the number is bigger than `Number.MAX_SAFE_INTEGER`. See [here](https://github.com/redis/node-redis/issues/2561).
228+
- `FT.PROFILE`: `profile` type is now `ReplyUnion`, which preserves the server's original response format. This change helps prevent issues with future updates to the debug response structure.
229+
- `FT.SUGGET`: Since Redis 8, the server returns `[]` instead of `null` when there are no suggestions
228230

229231
### Time Series
230232

docs/v5.md

+155-10
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,171 @@
11
# RESP3 Support
22

3-
TODO
3+
Redis Serialization Protocol version 3 (RESP3) is the newer protocol used for communication between Redis servers and clients. It offers more data types and richer semantics compared to RESP2.
4+
5+
## Enabling RESP3
6+
7+
To use RESP3, simply set the `RESP` option to `3` when creating a client:
48

59
```javascript
610
const client = createClient({
711
RESP: 3
812
});
913
```
1014

11-
```javascript
12-
// by default
13-
await client.hGetAll('key'); // Record<string, string>
15+
## Type Mapping
1416

15-
await client.withTypeMapping({
16-
[TYPES.MAP]: Map
17-
}).hGetAll('key'); // Map<string, string>
17+
Some [RESP types](./RESP.md) can be mapped to more than one JavaScript type. For example, "Blob String" can be mapped to `string` or `Buffer`. You can override the default type mapping using the `withTypeMapping` function:
18+
19+
```javascript
20+
await client.get('key'); // `string | null`
1821

19-
await client.withTypeMapping({
20-
[TYPES.MAP]: Map,
22+
const proxyClient = client.withTypeMapping({
2123
[TYPES.BLOB_STRING]: Buffer
22-
}).hGetAll('key'); // Map<string, Buffer>
24+
});
25+
26+
await proxyClient.get('key'); // `Buffer | null`
27+
```
28+
29+
## Unstable RESP3 Support
30+
31+
Some Redis modules (particularly the Search module) have responses that might change in future RESP3 implementations. These commands are marked with `unstableResp3: true` in the codebase.
32+
33+
To use these commands with RESP3, you must explicitly enable unstable RESP3 support:
34+
35+
```javascript
36+
const client = createClient({
37+
RESP: 3,
38+
unstableResp3: true
39+
});
40+
```
41+
42+
If you attempt to use these commands with RESP3 without enabling the `unstableResp3` flag, the client will throw an error with a message like:
43+
2344
```
45+
Some RESP3 results for Redis Query Engine responses may change. Refer to the readme for guidance
46+
```
47+
48+
### Commands Using Unstable RESP3
49+
50+
The following Redis commands and modules use the `unstableResp3` flag:
51+
- Many Search module commands (FT.*)
52+
- Stream commands like XREAD, XREADGROUP
53+
- Other modules with complex response structures
54+
55+
If you're working with these commands and want to use RESP3, make sure to enable unstable RESP3 support in your client configuration.
56+
57+
# Client-Side Caching
58+
59+
Redis 6.0 introduced client-side caching, which allows clients to locally cache command results and receive invalidation notifications from the server. This significantly reduces network roundtrips and latency for frequently accessed data.
60+
61+
### How It Works
62+
63+
1. When a cacheable command is executed, the client checks if the result is already in the cache
64+
2. If found and valid, it returns the cached result (no Redis server roundtrip)
65+
3. If not found, it executes the command and caches the result
66+
4. When Redis modifies keys, it sends invalidation messages to clients
67+
5. The client removes the invalidated entries from its cache
68+
69+
This mechanism ensures data consistency while providing significant performance benefits for read-heavy workloads.
70+
71+
## Requirements
72+
73+
Client-side caching in node-redis:
74+
- Requires RESP3 protocol (`RESP: 3` in client configuration)
75+
- Uses Redis server's invalidation mechanism to keep the cache in sync
76+
- Is completely disabled when using RESP2
77+
78+
## Limitations of Client-Side Caching
79+
80+
Currently, node-redis implements client-side caching only in "default" tracking mode. The implementation does not yet support the following Redis client-side caching modes:
81+
82+
- **Opt-In Mode**: Where clients explicitly indicate which specific keys they want to cache using the `CLIENT CACHING YES` command before each cacheable command.
83+
84+
- **Opt-Out Mode**: Where all keys are cached by default, and clients specify exceptions for keys they don't want to cache with `CLIENT UNTRACKING`.
85+
86+
- **Broadcasting Mode**: Where clients subscribe to invalidation messages for specific key prefixes without the server tracking individual client-key relationships.
87+
88+
These advanced caching modes offer more fine-grained control over caching behavior and may be supported in future node-redis releases. While node-redis doesn't implement these modes natively yet, the underlying Redis commands (`CLIENT TRACKING`, `CLIENT CACHING`, `CLIENT UNTRACKING`) are available if you need to implement these advanced tracking modes yourself.
89+
90+
91+
## Basic Configuration
92+
93+
To enable client-side caching with default settings:
94+
95+
```javascript
96+
const client = createClient({
97+
RESP: 3,
98+
clientSideCache: {
99+
// Cache configuration options
100+
maxEntries: 1000, // Maximum number of entries in the cache (0 = unlimited)
101+
ttl: 60000, // Time-to-live in milliseconds (0 = never expire)
102+
evictPolicy: "LRU" // Eviction policy (LRU or FIFO)
103+
}
104+
});
105+
```
106+
107+
### Cache Control
108+
109+
You can also create and control the cache instance directly:
110+
111+
```javascript
112+
// Import the cache provider
113+
const { BasicClientSideCache } = require('redis');
114+
115+
// Create a configurable cache instance
116+
const cache = new BasicClientSideCache({
117+
maxEntries: 5000,
118+
ttl: 30000
119+
});
120+
121+
// Create client with this cache
122+
const client = createClient({
123+
RESP: 3,
124+
clientSideCache: cache
125+
});
126+
127+
// Later you can:
128+
// Get cache statistics
129+
const hits = cache.cacheHits();
130+
const misses = cache.cacheMisses();
131+
132+
// Manually invalidate specific keys
133+
cache.invalidate('my-key');
134+
135+
// Clear the entire cache
136+
cache.clear();
137+
138+
// Listen for cache events
139+
cache.on('invalidate', (key) => {
140+
console.log(`Cache key invalidated: ${key}`);
141+
});
142+
```
143+
144+
### Working with Connection Pools
145+
146+
Client-side caching also works with connection pools:
147+
148+
```javascript
149+
const pool = createClientPool({
150+
RESP: 3
151+
}, {
152+
clientSideCache: {
153+
maxEntries: 10000,
154+
ttl: 60000
155+
},
156+
minimum: 5
157+
});
158+
```
159+
160+
For pools, you can use specialized cache providers like `BasicPooledClientSideCache` or `PooledNoRedirectClientSideCache` that handle connection events appropriately.
161+
162+
### Performance Considerations
163+
164+
- Configure appropriate `maxEntries` and `ttl` values based on your application needs
165+
- Monitor cache hit/miss rates to optimize settings
166+
- Consider memory usage on the client side when using large caches
167+
- Client-side caching works best for frequently accessed, relatively static data
168+
24169

25170
# Sentinel Support
26171

packages/client/lib/client/index.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,20 @@ export interface RedisClientOptions<
8282
*/
8383
commandOptions?: CommandOptions<TYPE_MAPPING>;
8484
/**
85-
* TODO
85+
* Client-side Caching configuration
86+
*
87+
* Enables client-side caching functionality for the client to reduce network
88+
* round-trips and improve performance for frequently accessed data.
89+
*
90+
* You can either:
91+
* 1. Provide an instance that implements the `ClientSideCacheProvider` abstract class
92+
* for complete control over cache behavior, or
93+
* 2. Provide a configuration object (`ClientSideCacheConfig`) to customize the
94+
* built-in cache implementation with your preferred settings
95+
*
96+
*
97+
* @see {@link ClientSideCacheProvider} - Abstract class for implementing custom cache providers
98+
* @see {@link ClientSideCacheConfig} - Configuration options for the built-in cache implementation
8699
*/
87100
clientSideCache?: ClientSideCacheProvider | ClientSideCacheConfig;
88101
}

packages/client/lib/sentinel/types.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,24 @@ export interface RedisSentinelOptions<
6262
* When `false`, the sentinel object will wait for the first available client from the pool.
6363
*/
6464
reserveClient?: boolean;
65+
6566
/**
66-
* TODO
67+
* Client-side Caching configuration
68+
*
69+
* Enables client-side caching functionality for the client to reduce network
70+
* round-trips and improve performance for frequently accessed data.
71+
*
72+
* You can either:
73+
* 1. Provide an instance that implements the `PooledClientSideCacheProvider` abstract class
74+
* for complete control over cache behavior, or
75+
* 2. Provide a configuration object (`ClientSideCacheConfig`) to customize the
76+
* built-in cache implementation with your preferred settings
77+
*
78+
*
79+
* @see {@link PooledClientSideCacheProvider} - Abstract class for implementing custom pooled cache providers
80+
* @see {@link ClientSideCacheConfig} - Configuration options for the built-in cache implementation
6781
*/
68-
clientSideCache?: PooledClientSideCacheProvider | ClientSideCacheConfig;
82+
clientSideCache?: PooledClientSideCacheProvider | ClientSideCacheConfig;
6983
}
7084

7185
export interface SentinelCommander<

0 commit comments

Comments
 (0)