ioredis 5.3.1 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,18 @@
1
- [![ioredis](https://cdn.jsdelivr.net/gh/luin/ioredis@b5e8c74/logo.svg)](https://github.com/luin/ioredis)
1
+ [![ioredis](https://cdn.jsdelivr.net/gh/redis/ioredis@b5e8c74/logo.svg)](https://github.com/redis/ioredis)
2
2
 
3
- [![Build Status](https://github.com/luin/ioredis/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/luin/ioredis/actions/workflows/release.yml?query=branch%3Amain)
3
+ [![Build Status](https://github.com/redis/ioredis/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/redis/ioredis/actions/workflows/release.yml?query=branch%3Amain)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/luin/ioredis/badge.svg?branch=main)](https://coveralls.io/github/luin/ioredis?branch=main)
5
- [![Join the chat at https://gitter.im/luin/ioredis](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/luin/ioredis?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
5
  [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
7
6
  [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
8
7
 
8
+ [![Discord](https://img.shields.io/discord/697882427875393627.svg?style=social&logo=discord)](https://discord.gg/redis)
9
+ [![Twitch](https://img.shields.io/twitch/status/redisinc?style=social)](https://www.twitch.tv/redisinc)
10
+ [![YouTube](https://img.shields.io/youtube/channel/views/UCD78lHSwYqMlyetR0_P4Vig?style=social)](https://www.youtube.com/redisinc)
11
+ [![Twitter](https://img.shields.io/twitter/follow/redisinc?style=social)](https://twitter.com/redisinc)
12
+
9
13
  A robust, performance-focused and full-featured [Redis](http://redis.io) client for [Node.js](https://nodejs.org).
10
14
 
11
- Supports Redis >= 2.6.12 and (Node.js >= 12.22.0). Completely compatible with Redis 7.x.
15
+ Supports Redis >= 2.6.12. Completely compatible with Redis 7.x.
12
16
 
13
17
  # Features
14
18
 
@@ -20,9 +24,9 @@ used in the world's biggest online commerce company [Alibaba](http://www.alibaba
20
24
  2. Delightful API 😄. It works with Node callbacks and Native promises.
21
25
  3. Transformation of command arguments and replies.
22
26
  4. Transparent key prefixing.
23
- 5. Abstraction for Lua scripting, allowing you to [define custom commands](https://github.com/luin/ioredis#lua-scripting).
24
- 6. Supports [binary data](https://github.com/luin/ioredis#handle-binary-data).
25
- 7. Supports [TLS](https://github.com/luin/ioredis#tls-options) 🔒.
27
+ 5. Abstraction for Lua scripting, allowing you to [define custom commands](https://github.com/redis/ioredis#lua-scripting).
28
+ 6. Supports [binary data](https://github.com/redis/ioredis#handle-binary-data).
29
+ 7. Supports [TLS](https://github.com/redis/ioredis#tls-options) 🔒.
26
30
  8. Supports offline queue and ready checking.
27
31
  9. Supports ES6 types, such as `Map` and `Set`.
28
32
  10. Supports GEO commands 📍.
@@ -44,46 +48,12 @@ used in the world's biggest online commerce company [Alibaba](http://www.alibaba
44
48
 
45
49
  Refer to [CHANGELOG.md](CHANGELOG.md) for features and bug fixes introduced in v5.
46
50
 
47
- 🚀 [Upgrading from v4 to v5](https://github.com/luin/ioredis/wiki/Upgrading-from-v4-to-v5)
51
+ 🚀 [Upgrading from v4 to v5](https://github.com/redis/ioredis/wiki/Upgrading-from-v4-to-v5)
48
52
 
49
53
  # Links
50
54
 
51
- - [API Documentation](https://luin.github.io/ioredis/) ([Redis](https://luin.github.io/ioredis/classes/Redis.html), [Cluster](https://luin.github.io/ioredis/classes/Cluster.html))
55
+ - [API Documentation](https://redis.github.io/ioredis/) ([Redis](https://redis.github.io/ioredis/classes/Redis.html), [Cluster](https://redis.github.io/ioredis/classes/Cluster.html))
52
56
  - [Changelog](CHANGELOG.md)
53
- - [Migrating from node_redis](https://github.com/luin/ioredis/wiki/Migrating-from-node_redis)
54
-
55
- <hr>
56
-
57
- # Sponsors
58
-
59
- ### Upstash: Serverless Database for Redis
60
-
61
- <a href="https://upstash.com/?utm_source=ioredis"><img align="right" width="320" src="resources/upstash.png" alt="Upstash"></a>
62
-
63
- Upstash is a Serverless Database with Redis/REST API and durable storage. It is the perfect database for your applications thanks to its per request pricing and low latency data.
64
-
65
- [Start for free in 30 seconds!](https://upstash.com/?utm_source=ioredis)
66
-
67
- <br clear="both"/>
68
-
69
- ### Medis: Redis GUI for macOS
70
-
71
- <a href="https://getmedis.com/"><img align="right" width="404" src="resources/medis.png" alt="Download on the App Store"></a>
72
-
73
- Looking for a Redis GUI for macOS, Windows and Linux? Here's [Medis](https://getmedis.com/)!
74
-
75
- Medis is an open-sourced, beautiful, easy-to-use Redis GUI management application.
76
-
77
- Medis starts with all the basic features you need:
78
-
79
- - Keys viewing/editing
80
- - SSH Tunnel for connecting with remote servers
81
- - Terminal for executing custom commands
82
- - And other awesome features...
83
-
84
- [Medis 1 is open sourced on GitHub](https://github.com/luin/medis)
85
-
86
- <br clear="both"/>
87
57
 
88
58
  <hr>
89
59
 
@@ -156,7 +126,7 @@ See the `examples/` folder for more examples. For example:
156
126
  - [Streams](examples/stream.js)
157
127
  - [Redis Modules](examples/module.js) e.g. RedisJSON
158
128
 
159
- All Redis commands are supported. See [the documentation](https://luin.github.io/ioredis/classes/Redis.html) for details.
129
+ All Redis commands are supported. See [the documentation](https://redis.github.io/ioredis/classes/Redis.html) for details.
160
130
 
161
131
  ## Connect to Redis
162
132
 
@@ -188,7 +158,7 @@ new Redis("redis://:authpassword@127.0.0.1:6380/4");
188
158
  new Redis("redis://username:authpassword@127.0.0.1:6380/4");
189
159
  ```
190
160
 
191
- See [API Documentation](https://luin.github.io/ioredis/index.html#RedisOptions) for all available options.
161
+ See [API Documentation](https://redis.github.io/ioredis/index.html#RedisOptions) for all available options.
192
162
 
193
163
  ## Pub/Sub
194
164
 
@@ -302,6 +272,16 @@ async function listenForMessage(lastId = "$") {
302
272
  listenForMessage();
303
273
  ```
304
274
 
275
+ ## Expiration
276
+
277
+ Redis can set a timeout to expire your key, after the timeout has expired the key will be automatically deleted. (You can find the [official Expire documentation](https://redis.io/commands/expire/) to understand better the different parameters you can use), to set your key to expire in 60 seconds, we will have the following code:
278
+
279
+ ```javascript
280
+ redis.set("key", "data", "EX", 60);
281
+ // Equivalent to redis command "SET key data EX 60", because on ioredis set method,
282
+ // all arguments are passed directly to the redis server.
283
+ ```
284
+
305
285
  ## Handle Binary Data
306
286
 
307
287
  Binary data support is out of the box. Pass buffers to send binary data:
@@ -559,8 +539,8 @@ This feature allows you to specify a string that will automatically be prepended
559
539
  to all the keys in a command, which makes it easier to manage your key
560
540
  namespaces.
561
541
 
562
- **Warning** This feature won't apply to commands like [KEYS](http://redis.io/commands/KEYS) and [SCAN](http://redis.io/commands/scan) that take patterns rather than actual keys([#239](https://github.com/luin/ioredis/issues/239)),
563
- and this feature also won't apply to the replies of commands even if they are key names ([#325](https://github.com/luin/ioredis/issues/325)).
542
+ **Warning** This feature won't apply to commands like [KEYS](http://redis.io/commands/KEYS) and [SCAN](http://redis.io/commands/scan) that take patterns rather than actual keys([#239](https://github.com/redis/ioredis/issues/239)),
543
+ and this feature also won't apply to the replies of commands even if they are key names ([#325](https://github.com/redis/ioredis/issues/325)).
564
544
 
565
545
  ```javascript
566
546
  const fooRedis = new Redis({ keyPrefix: "foo:" });
@@ -884,6 +864,15 @@ Alternatively, specify the connection through a [`rediss://` URL](https://www.ia
884
864
  const redis = new Redis("rediss://redis.my-service.com");
885
865
  ```
886
866
 
867
+ If you do not want to use a connection string, you can also specify an empty `tls: {}` object:
868
+
869
+ ```javascript
870
+ const redis = new Redis({
871
+ host: "redis.my-service.com",
872
+ tls: {},
873
+ });
874
+ ```
875
+
887
876
  ### TLS Profiles
888
877
 
889
878
  > **Warning**
@@ -1412,19 +1401,11 @@ I'm happy to receive bug reports, fixes, documentation enhancements, and any oth
1412
1401
 
1413
1402
  And since I'm not a native English speaker, if you find any grammar mistakes in the documentation, please also let me know. :)
1414
1403
 
1415
- # Become a Sponsor
1416
-
1417
- Open source is hard and time-consuming. If you want to invest in ioredis's future you can become a sponsor and make us spend more time on this library's improvements and new features.
1418
-
1419
- <a href="https://opencollective.com/ioredis"><img src="https://opencollective.com/ioredis/tiers/sponsor.svg?avatarHeight=36"></a>
1420
-
1421
- Thank you for using ioredis :-)
1422
-
1423
1404
  # Contributors
1424
1405
 
1425
1406
  This project exists thanks to all the people who contribute:
1426
1407
 
1427
- <a href="https://github.com/luin/ioredis/graphs/contributors"><img src="https://opencollective.com/ioredis/contributors.svg?width=890&showBtn=false" /></a>
1408
+ <a href="https://github.com/redis/ioredis/graphs/contributors"><img src="https://opencollective.com/ioredis/contributors.svg?width=890&showBtn=false" /></a>
1428
1409
 
1429
1410
  # License
1430
1411
 
package/built/Redis.d.ts CHANGED
@@ -63,6 +63,7 @@ declare class Redis extends Commander implements DataHandledable {
63
63
  private connectionEpoch;
64
64
  private retryAttempts;
65
65
  private manuallyClosing;
66
+ private socketTimeoutTimer;
66
67
  private _autoPipelines;
67
68
  private _runningAutoPipelines;
68
69
  constructor(port: number, host: string, options: RedisOptions);
@@ -159,6 +160,7 @@ declare class Redis extends Commander implements DataHandledable {
159
160
  * @ignore
160
161
  */
161
162
  sendCommand(command: Command, stream?: WriteableStream): unknown;
163
+ private setSocketTimeout;
162
164
  scanStream(options?: ScanStreamOptions): ScanStream;
163
165
  scanBufferStream(options?: ScanStreamOptions): ScanStream;
164
166
  sscanStream(key: string, options?: ScanStreamOptions): ScanStream;
@@ -207,6 +209,20 @@ declare class Redis extends Commander implements DataHandledable {
207
209
  private _readyCheck;
208
210
  }
209
211
  interface Redis extends EventEmitter {
212
+ on(event: "message", cb: (channel: string, message: string) => void): this;
213
+ once(event: "message", cb: (channel: string, message: string) => void): this;
214
+ on(event: "messageBuffer", cb: (channel: Buffer, message: Buffer) => void): this;
215
+ once(event: "messageBuffer", cb: (channel: Buffer, message: Buffer) => void): this;
216
+ on(event: "pmessage", cb: (pattern: string, channel: string, message: string) => void): this;
217
+ once(event: "pmessage", cb: (pattern: string, channel: string, message: string) => void): this;
218
+ on(event: "pmessageBuffer", cb: (pattern: string, channel: Buffer, message: Buffer) => void): this;
219
+ once(event: "pmessageBuffer", cb: (pattern: string, channel: Buffer, message: Buffer) => void): this;
220
+ on(event: "error", cb: (error: Error) => void): this;
221
+ once(event: "error", cb: (error: Error) => void): this;
222
+ on(event: RedisStatus, cb: () => void): this;
223
+ once(event: RedisStatus, cb: () => void): this;
224
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
225
+ once(event: string | symbol, listener: (...args: any[]) => void): this;
210
226
  }
211
227
  interface Redis extends Transaction {
212
228
  }
package/built/Redis.js CHANGED
@@ -401,6 +401,9 @@ class Redis extends Commander_1.default {
401
401
  if (Command_1.default.checkFlag("WILL_DISCONNECT", command.name)) {
402
402
  this.manuallyClosing = true;
403
403
  }
404
+ if (this.options.socketTimeout !== undefined && this.socketTimeoutTimer === undefined) {
405
+ this.setSocketTimeout();
406
+ }
404
407
  }
405
408
  if (command.name === "select" && (0, utils_1.isInt)(command.args[0])) {
406
409
  const db = parseInt(command.args[0], 10);
@@ -412,6 +415,22 @@ class Redis extends Commander_1.default {
412
415
  }
413
416
  return command.promise;
414
417
  }
418
+ setSocketTimeout() {
419
+ this.socketTimeoutTimer = setTimeout(() => {
420
+ this.stream.destroy(new Error(`Socket timeout. Expecting data, but didn't receive any in ${this.options.socketTimeout}ms.`));
421
+ this.socketTimeoutTimer = undefined;
422
+ }, this.options.socketTimeout);
423
+ // this handler must run after the "data" handler in "DataHandler"
424
+ // so that `this.commandQueue.length` will be updated
425
+ this.stream.once("data", () => {
426
+ console.log('GOT DATA, CLEARING TIMER');
427
+ clearTimeout(this.socketTimeoutTimer);
428
+ this.socketTimeoutTimer = undefined;
429
+ if (this.commandQueue.length === 0)
430
+ return;
431
+ this.setSocketTimeout();
432
+ });
433
+ }
415
434
  scanStream(options) {
416
435
  return this.createScanStream("scan", { options });
417
436
  }
@@ -44,6 +44,7 @@ declare class Cluster extends Commander {
44
44
  private slotsTimer;
45
45
  private reconnectTimeout;
46
46
  private isRefreshing;
47
+ private _refreshSlotsCacheCallbacks;
47
48
  private _autoPipelines;
48
49
  private _runningAutoPipelines;
49
50
  private _readyDelayedCallbacks;
@@ -46,6 +46,7 @@ class Cluster extends Commander_1.default {
46
46
  this.delayQueue = new DelayQueue_1.default();
47
47
  this.offlineQueue = new Deque();
48
48
  this.isRefreshing = false;
49
+ this._refreshSlotsCacheCallbacks = [];
49
50
  this._autoPipelines = new Map();
50
51
  this._runningAutoPipelines = new Set();
51
52
  this._readyDelayedCallbacks = [];
@@ -287,19 +288,20 @@ class Cluster extends Commander_1.default {
287
288
  * @ignore
288
289
  */
289
290
  refreshSlotsCache(callback) {
291
+ if (callback) {
292
+ this._refreshSlotsCacheCallbacks.push(callback);
293
+ }
290
294
  if (this.isRefreshing) {
291
- if (callback) {
292
- process.nextTick(callback);
293
- }
294
295
  return;
295
296
  }
296
297
  this.isRefreshing = true;
297
298
  const _this = this;
298
299
  const wrapper = (error) => {
299
300
  this.isRefreshing = false;
300
- if (callback) {
301
+ for (const callback of this._refreshSlotsCacheCallbacks) {
301
302
  callback(error);
302
303
  }
304
+ this._refreshSlotsCacheCallbacks = [];
303
305
  };
304
306
  const nodes = (0, utils_1.shuffle)(this.connectionPool.getNodes());
305
307
  let lastNodeError = null;
@@ -11,6 +11,13 @@ export interface CommonRedisOptions extends CommanderOptions {
11
11
  * a "Command timed out" error will be thrown.
12
12
  */
13
13
  commandTimeout?: number;
14
+ /**
15
+ * If the socket does not receive data within a set number of milliseconds:
16
+ * 1. the socket is considered "dead" and will be destroyed
17
+ * 2. the client will reject any running commands (altought they might have been processed by the server)
18
+ * 3. the reconnect strategy will kick in (depending on the configuration)
19
+ */
20
+ socketTimeout?: number;
14
21
  /**
15
22
  * Enable/disable keep-alive functionality.
16
23
  * @link https://nodejs.org/api/net.html#socketsetkeepaliveenable-initialdelay
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ioredis",
3
- "version": "5.3.1",
3
+ "version": "5.4.0",
4
4
  "description": "A robust, performance-focused and full-featured Redis client for Node.js.",
5
5
  "main": "./built/index.js",
6
6
  "types": "./built/index.d.ts",