Skip to content

Commit c188a5c

Browse files
leibaleguyroyse
andcommitted
docs
Co-authored-by: Guy Royse <[email protected]>
1 parent 826296f commit c188a5c

File tree

7 files changed

+122
-107
lines changed

7 files changed

+122
-107
lines changed

docs/FAQ.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ If don't want to queue commands in memory until a new socket is established, set
1010

1111
## How are commands batched?
1212

13-
Commands are pipelined using [`queueMicrotask`](https://nodejs.org/api/globals.html#globals_queuemicrotask_callback).
13+
Commands are pipelined using [`setImmediate`](https://nodejs.org/api/globals.html#setimmediatecallback-args).
1414

1515
If `socket.write()` returns `false`—meaning that ["all or part of the data was queued in user memory"](https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback:~:text=all%20or%20part%20of%20the%20data%20was%20queued%20in%20user%20memory)—the commands will stack in memory until the [`drain`](https://nodejs.org/api/net.html#net_event_drain) event is fired.
1616

docs/RESP.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
# RESP
1+
# Mapping RESP types
22

3-
## Type Mapping
3+
RESP, which stands for **R**edis **SE**rialization **P**rotocol, is the protocol used by Redis to communicate with clients. This document shows how RESP types can be mapped to JavaScript types. You can learn more about RESP itself in the [offical documentation](https://redis.io/docs/reference/protocol-spec/).
44

5-
## RESP2 -> JS
5+
By default, each type is mapped to the first option in the lists below. To change this, configure a [`typeMapping`](.).
6+
7+
## RESP2
68

79
- Integer (`:`) => `number`
810
- Simple String (`+`) => `string | Buffer`
911
- Blob String (`$`) => `string | Buffer`
1012
- Simple Error (`-`) => `ErrorReply`
1113
- Array (`*`) => `Array`
1214

13-
## RESP3 -> JS
15+
> NOTE: the first type is the default type
16+
17+
## RESP3
1418

1519
- Null (`_`) => `null`
1620
- Boolean (`#`) => `boolean`
@@ -29,11 +33,11 @@
2933

3034
> NOTE: the first type is the default type
3135
32-
## Map keys and Set members
36+
### Map keys and Set members
3337

34-
When decoding Map to `Map | object` or Set to `Set`, keys/members (respectively) of type "Simple String" or "Blob String" will be decoded as `string`s (ignoring type mapping) to allow lookup by type. If you need them as `Buffer`s, make sure to decode `Map`s/`Set`s as `Array`s.
38+
When decoding a Map to `Map | object` or a Set to `Set`, keys and members of type "Simple String" or "Blob String" will be decoded as `string`s which enables lookups by value, ignoring type mapping. If you want them as `Buffer`s, decode them as `Array`s instead.
3539

36-
## Not Implemented
40+
### Not Implemented
3741

3842
These parts of RESP3 are not yet implemented in Redis itself (at the time of writing), so are not yet implemented in the Node-Redis client either:
3943

docs/isolated-execution.md renamed to docs/blocking-commands.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
### Blocking Commands
2+
3+
Any command can be run on a new connection by specifying the `isolated` option. The newly created connection is closed when the command's `Promise` is fulfilled.
4+
5+
This pattern works especially well for blocking commands—such as `BLPOP` and `BLMOVE`:
6+
7+
```typescript
8+
import { commandOptions } from 'redis';
9+
10+
const blPopPromise = client.isolated().blPop(
11+
'key',
12+
0
13+
);
14+
15+
await client.lPush('key', ['1', '2']);
16+
17+
await blPopPromise; // '2'
18+
```
19+
20+
To learn more about isolated execution, check out the [guide](../../docs/isolated-execution.md).
21+
122
# Isolated Execution
223

324
Sometimes you want to run your commands on an exclusive connection. There are a few reasons to do this:

docs/command-options.md

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
> :warning: The command options API in v5 has breaking changes from the previous version. For more details, refer to the [v4-to-v5 guide](./v4-to-v5.md#command-options).
44
5-
TODO
5+
Command Options are used to create "proxy clients" that change the behavior of executed commands. See the sections below for details.
66

77
## Type Mapping
88

9-
Some RESP types can be mapped to more than one JavaScript type. For example, "Blob String" can be mapped to `string` or `Buffer`.
10-
You can override the default type mapping using the `withTypeMapping` function:
9+
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:
1110

1211
```javascript
1312
await client.get('key'); // `string | null`
@@ -23,48 +22,47 @@ See [RESP](./RESP.md) for a full list of types.
2322

2423
## Abort Signal
2524

26-
Commands can be aborted using the [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) API:
25+
The client [batches commands](./FAQ.md#how-are-commands-batched) before sending them to Redis. Commands that haven't been written to the socket yet can be aborted using the [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) API:
2726

2827
```javascript
29-
30-
const controller = new AbortController();
31-
controller.abort();
28+
const controller = new AbortController(),
29+
client = client.withAbortSignal(controller.signal);
3230

3331
try {
34-
await client.withAbortSignal(controller.signal).get('key');
32+
const promise = client.get('key');
33+
controller.abort();
34+
await promise;
3535
} catch (err) {
3636
// AbortError
3737
}
3838
```
3939

40-
> NOTE: Commands that are already written to the socket cannot be aborted.
41-
4240
## ASAP
4341

44-
Commands that are executed in the "asap" mode are added to the top of the queue. This is useful to ensure that commands are executed before other commands that are already in the queue.
42+
Commands that are executed in the "asap" mode are added to the beginning of the "to sent" queue.
4543

4644
```javascript
4745
const asapClient = client.asap();
48-
49-
client.on('connect', () => {
50-
asapClient.clientSetName('my-name')
51-
.catch(err => console.error('CLIENT SETNAME error', err));
52-
});
46+
await asapClient.ping();
5347
```
5448

5549
## `withCommandOptions`
5650

57-
The `withCommandOptions` overrides all of the command options, without reusing any existing ones:
51+
You can set all of the above command options in a single call with the `withCommandOptions` function:
5852

5953
```javascript
60-
const bufferClient = client.withTypeMapping({
61-
[TYPES.BLOB_STRING]: Buffer
54+
client.withCommandOptions({
55+
typeMapping: ...,
56+
abortSignal: ...,
57+
asap: ...
6258
});
59+
```
6360

64-
await bufferClient.get('key'); // `Buffer | null`
65-
66-
// reset all command options
67-
const defaultClient = client.withCommandOptions({});
61+
If any of the above options are omitted, the default value will be used. For example, the following client would **not** be in ASAP mode:
6862

69-
await defaultClient.get('key'); // `string | null`
63+
```javascript
64+
client.asap().withCommandOptions({
65+
typeMapping: ...,
66+
abortSignal: ...
67+
});
7068
```

docs/v4-to-v5.md

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,15 @@ for more information, see the [Scan Iterators guide](./scan-iterators.md).
6161

6262
## Legacy Mode
6363

64-
TODO
64+
In the previous version, you could access "legacy" mode by creating a client and passing in `{ legacyMode: true }`. Now, you can create one off of an existing client by calling the `.legacy()` function. This allows easier access to both APIs and enables better TypeScript support.
6565

6666
```javascript
67-
const client = createClient(),
68-
legacyClient = client.legacy();
69-
70-
// use `client` for the new API
67+
// use `client` for the current API
68+
const client = createClient();
7169
await client.set('key', 'value');
7270

7371
// use `legacyClient` for the "legacy" API
72+
const legacyClient = client.legacy();
7473
legacyClient.set('key', 'value', (err, reply) => {
7574
// ...
7675
});
@@ -79,14 +78,48 @@ legacyClient.set('key', 'value', (err, reply) => {
7978
## Isolation Pool
8079

8180
TODO
82-
The `isolationPool` has been moved to it's on class `ClientPool`. You can create pool from a client using `client.createPool()`.
8381

84-
## Cluster MULTI
82+
```javascript
83+
await client.sendCommand(['GET', 'key']);
84+
const pool = client.createPool({
85+
min: 0,
86+
max: Infinity
87+
});
88+
await pool.blPop('key');
89+
await pool.sendCommand(['GET', 'key']);
90+
await pool.use(client => client.blPop());
91+
92+
await cluster.sendCommand('key', true, ['GET', 'key']);
93+
const clusterPool = cluster.createPool({
94+
min: 0,
95+
max: Infinity
96+
});
97+
await clusterPool.blPop('key');
98+
await clusterPool.sendCommand('key', true, ['GET', 'key']);
99+
await clusterPool.use(client => client.blPop());
100+
```
101+
102+
## Cluster `MULTI`
85103

86-
Cluster MULTI supports readonly/replicas
87-
`cluster.multi.addCommand` now requires `isReadonly` as the second argument, to match `cluster.sendCommand`
104+
In v4, `cluster.multi()` did not support executing commands on replicas, even if they were readonly.
88105

89-
TODO
106+
```javascript
107+
// this might execute on a replica, depending on configuration
108+
await cluster.sendCommand('key', true, ['GET', 'key']);
109+
110+
// this always executes on a master
111+
await cluster.multi()
112+
.addCommand('key', ['GET', 'key'])
113+
.exec();
114+
```
115+
116+
To support executing commands on replicas, `cluster.multi().addCommand` now requires `isReadonly` as the second argument, which matches the signature of `cluster.sendCommand`:
117+
118+
```javascript
119+
await cluster.multi()
120+
.addCommand('key', true, ['GET', 'key'])
121+
.exec();
122+
```
90123

91124
## Commands
92125

docs/v5.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
# RESP3 Support
22

3-
[RESP3](./RESP3.md)
3+
TODO
44

55
```javascript
66
const client = createClient({
77
RESP: 3
88
});
9+
```
910

10-
client.on('error', err => console.error(err));
11-
12-
await client.connect();
13-
14-
client.hGetAll('key'); // Record<string, string>
11+
```javascript
12+
// by default
13+
await client.hGetAll('key'); // Record<string, string>
1514

16-
client.withTypeMapping({
15+
await client.withTypeMapping({
1716
[TYPES.MAP]: Map
1817
}).hGetAll('key'); // Map<string, string>
1918

20-
client.withTypeMapping({
19+
await client.withTypeMapping({
2120
[TYPES.MAP]: Map,
2221
[TYPES.BLOB_STRING]: Buffer
2322
}).hGetAll('key'); // Map<string, Buffer>

packages/redis/README.md

Lines changed: 17 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ await client.connect();
4242

4343
await client.set('key', 'value');
4444
const value = await client.get('key');
45-
client.destroy();
45+
await client.close();
4646
```
4747

48+
> :warning: You **MUST** listen to `error` events. If a client doesn't have at least one `error` listener registered and an `error` occurs, that error will be thrown and the Node.js process will exit. See the [`EventEmitter` docs](https://nodejs.org/api/events.html#events_error_events) for more details.
49+
4850
The above code connects to localhost on port 6379. To connect to a different host or port, use a connection string in the format `redis[s]://[[username][:password]@][host][:port][/db-number]`:
4951

5052
```javascript
@@ -83,21 +85,14 @@ await client.set('key', 'value', {
8385
});
8486
```
8587

86-
Replies will be transformed into useful data structures:
88+
Replies will be mapped to useful data structures:
8789

8890
```typescript
8991
await client.hGetAll('key'); // { field1: 'value1', field2: 'value2' }
9092
await client.hVals('key'); // ['value1', 'value2']
9193
```
9294

93-
`Buffer`s are supported as well:
94-
95-
```typescript
96-
await client.hSet('key', 'field', Buffer.from('value')); // 'OK'
97-
await client.withTypeMapping({
98-
[TYPES.BLOB_STRING]: Buffer
99-
}).hGetAll('key'); // { field: <Buffer 76 61 6c 75 65> }
100-
```
95+
> NOTE: you can change the default type mapping. See the [Type Mapping](../../docs/command-options.md#type-mapping) documentation for more information.
10196
10297
### Unsupported Redis Commands
10398

@@ -109,37 +104,12 @@ await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'
109104
await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']
110105
```
111106

112-
### Links
113-
- [Multi](../../docs/multi.md).
114-
- [Pub/Sub](../../docs/pub-sub.md).
115-
- [Scan Iterators](../../docs/scan-iterators.md).
116-
- [Programmability](../../docs/programmability.md).
117-
118-
### Blocking Commands
119-
120-
Any command can be run on a new connection by specifying the `isolated` option. The newly created connection is closed when the command's `Promise` is fulfilled.
121-
122-
This pattern works especially well for blocking commands—such as `BLPOP` and `BLMOVE`:
123-
124-
```typescript
125-
import { commandOptions } from 'redis';
126-
127-
const blPopPromise = client.isolated().blPop(
128-
'key',
129-
0
130-
);
131-
132-
await client.lPush('key', ['1', '2']);
133-
134-
await blPopPromise; // '2'
135-
```
136-
137-
To learn more about isolated execution, check out the [guide](../../docs/isolated-execution.md).
138-
139107
### Disconnecting
140108

141109
There are two functions that disconnect a client from the Redis server. In most scenarios you should use `.close()` to ensure that pending commands are sent to Redis before closing a connection.
142110

111+
> :warning: The `.quit()` and `.disconnect()` methods have been deprecated in v5. For more details, refer to the [v4-to-v5 guide](../../docs/v4-to-v5.md#quit-vs-disconnect).
112+
143113
#### `.close()`
144114

145115
```typescript
@@ -180,26 +150,6 @@ await Promise.all([
180150
]);
181151
```
182152

183-
### Aborting Commands
184-
185-
If you want to abort a command, you can use the `AbortController` API:
186-
187-
```typescript
188-
const controller = new AbortController();
189-
190-
client.withAbortSignal(contoller.signal).get('key').catch(err => {
191-
// AbortError
192-
});
193-
194-
controller.abort();
195-
```
196-
197-
> :watning: commands can only be aborted before they are sent to Redis. Once a command is sent (written on the socket), it cannot be aborted.
198-
199-
### Clustering
200-
201-
Check out the [Clustering Guide](../../docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
202-
203153
### Events
204154

205155
The Node Redis client class is an Nodejs EventEmitter and it emits an event each time the network status changes:
@@ -242,3 +192,13 @@ Thank you to all the people who already contributed to Node Redis!
242192
## License
243193

244194
This repository is licensed under the "MIT" license. See [LICENSE](../../LICENSE).
195+
196+
### Links
197+
198+
- [Multi](../../docs/multi.md).
199+
- [Pub/Sub](../../docs/pub-sub.md).
200+
- [Scan Iterators](../../docs/scan-iterators.md).
201+
- [Programmability](../../docs/programmability.md).
202+
- [Command Options](../../docs/command-options.md).
203+
- [Blocking Commands](../../docs/blocking-commands.md).
204+
- [Clustering](../../docs/clustering.md).

0 commit comments

Comments
 (0)