You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-10 11:43:01 +03:00
As per the docs, unstableResp3 commands should throw when client is created with { RESP: 3, unstableResp3: false|undefined } fixes #2989
189 lines
5.1 KiB
Markdown
189 lines
5.1 KiB
Markdown
# RESP3 Support
|
|
|
|
Node Redis v5 adds support for [RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md), 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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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 Commands
|
|
|
|
Some Redis 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:
|
|
|
|
```javascript
|
|
const client = createClient({
|
|
RESP: 3,
|
|
unstableResp3: true
|
|
});
|
|
```
|
|
|
|
The following commands have unstable RESP3 implementations:
|
|
|
|
1. **Stream Commands**:
|
|
- `XREAD` and `XREADGROUP` - The response format differs between RESP2 and RESP3
|
|
|
|
2. **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`
|
|
|
|
3. **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
|
|
|
|
[Sentinel](./sentinel.md)
|
|
|
|
# `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:
|
|
|
|
```javascript
|
|
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](https://redis.io/docs/manual/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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
// 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:
|
|
|
|
```javascript
|
|
const client = createClientPool({RESP: 3}, {
|
|
clientSideCache: {
|
|
ttl: 0,
|
|
maxEntries: 0,
|
|
evictPolicy: "LRU"
|
|
},
|
|
minimum: 5
|
|
});
|
|
```
|
|
|
|
For a controllable pooled cache:
|
|
|
|
```javascript
|
|
import { BasicPooledClientSideCache } from 'redis';
|
|
|
|
const cache = new BasicPooledClientSideCache({
|
|
ttl: 0,
|
|
maxEntries: 0,
|
|
evictPolicy: "LRU"
|
|
});
|
|
|
|
const client = createClientPool({RESP: 3}, {
|
|
clientSideCache: cache,
|
|
minimum: 5
|
|
});
|
|
```
|