ioredis-om 5.10.2

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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1571 -0
  3. package/built/Command.d.ts +166 -0
  4. package/built/Command.js +450 -0
  5. package/built/DataHandler.d.ts +37 -0
  6. package/built/DataHandler.js +224 -0
  7. package/built/Pipeline.d.ts +31 -0
  8. package/built/Pipeline.js +342 -0
  9. package/built/Redis.d.ts +243 -0
  10. package/built/Redis.js +800 -0
  11. package/built/ScanStream.d.ts +23 -0
  12. package/built/ScanStream.js +51 -0
  13. package/built/Script.d.ts +11 -0
  14. package/built/Script.js +62 -0
  15. package/built/SubscriptionSet.d.ts +14 -0
  16. package/built/SubscriptionSet.js +41 -0
  17. package/built/autoPipelining.d.ts +8 -0
  18. package/built/autoPipelining.js +167 -0
  19. package/built/cluster/ClusterOptions.d.ts +172 -0
  20. package/built/cluster/ClusterOptions.js +22 -0
  21. package/built/cluster/ClusterSubscriber.d.ts +29 -0
  22. package/built/cluster/ClusterSubscriber.js +223 -0
  23. package/built/cluster/ClusterSubscriberGroup.d.ts +108 -0
  24. package/built/cluster/ClusterSubscriberGroup.js +373 -0
  25. package/built/cluster/ConnectionPool.d.ts +37 -0
  26. package/built/cluster/ConnectionPool.js +154 -0
  27. package/built/cluster/DelayQueue.d.ts +20 -0
  28. package/built/cluster/DelayQueue.js +53 -0
  29. package/built/cluster/ShardedSubscriber.d.ts +36 -0
  30. package/built/cluster/ShardedSubscriber.js +147 -0
  31. package/built/cluster/index.d.ts +163 -0
  32. package/built/cluster/index.js +937 -0
  33. package/built/cluster/util.d.ts +25 -0
  34. package/built/cluster/util.js +100 -0
  35. package/built/connectors/AbstractConnector.d.ts +12 -0
  36. package/built/connectors/AbstractConnector.js +26 -0
  37. package/built/connectors/ConnectorConstructor.d.ts +5 -0
  38. package/built/connectors/ConnectorConstructor.js +2 -0
  39. package/built/connectors/SentinelConnector/FailoverDetector.d.ts +11 -0
  40. package/built/connectors/SentinelConnector/FailoverDetector.js +45 -0
  41. package/built/connectors/SentinelConnector/SentinelIterator.d.ts +13 -0
  42. package/built/connectors/SentinelConnector/SentinelIterator.js +37 -0
  43. package/built/connectors/SentinelConnector/index.d.ts +72 -0
  44. package/built/connectors/SentinelConnector/index.js +305 -0
  45. package/built/connectors/SentinelConnector/types.d.ts +21 -0
  46. package/built/connectors/SentinelConnector/types.js +2 -0
  47. package/built/connectors/StandaloneConnector.d.ts +17 -0
  48. package/built/connectors/StandaloneConnector.js +69 -0
  49. package/built/connectors/index.d.ts +3 -0
  50. package/built/connectors/index.js +7 -0
  51. package/built/constants/TLSProfiles.d.ts +9 -0
  52. package/built/constants/TLSProfiles.js +149 -0
  53. package/built/errors/ClusterAllFailedError.d.ts +7 -0
  54. package/built/errors/ClusterAllFailedError.js +15 -0
  55. package/built/errors/MaxRetriesPerRequestError.d.ts +5 -0
  56. package/built/errors/MaxRetriesPerRequestError.js +14 -0
  57. package/built/errors/index.d.ts +2 -0
  58. package/built/errors/index.js +5 -0
  59. package/built/index.d.ts +44 -0
  60. package/built/index.js +62 -0
  61. package/built/redis/RedisOptions.d.ts +197 -0
  62. package/built/redis/RedisOptions.js +58 -0
  63. package/built/redis/event_handler.d.ts +4 -0
  64. package/built/redis/event_handler.js +315 -0
  65. package/built/tracing.d.ts +26 -0
  66. package/built/tracing.js +96 -0
  67. package/built/transaction.d.ts +13 -0
  68. package/built/transaction.js +100 -0
  69. package/built/types.d.ts +33 -0
  70. package/built/types.js +2 -0
  71. package/built/utils/Commander.d.ts +50 -0
  72. package/built/utils/Commander.js +117 -0
  73. package/built/utils/RedisCommander.d.ts +8950 -0
  74. package/built/utils/RedisCommander.js +7 -0
  75. package/built/utils/applyMixin.d.ts +3 -0
  76. package/built/utils/applyMixin.js +8 -0
  77. package/built/utils/argumentParsers.d.ts +14 -0
  78. package/built/utils/argumentParsers.js +74 -0
  79. package/built/utils/debug.d.ts +16 -0
  80. package/built/utils/debug.js +95 -0
  81. package/built/utils/index.d.ts +124 -0
  82. package/built/utils/index.js +332 -0
  83. package/built/utils/lodash.d.ts +4 -0
  84. package/built/utils/lodash.js +9 -0
  85. package/package.json +103 -0
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const util_1 = require("./util");
4
+ const utils_1 = require("../utils");
5
+ const Redis_1 = require("../Redis");
6
+ const debug = (0, utils_1.Debug)("cluster:subscriber");
7
+ class ClusterSubscriber {
8
+ constructor(connectionPool, emitter, isSharded = false) {
9
+ this.connectionPool = connectionPool;
10
+ this.emitter = emitter;
11
+ this.isSharded = isSharded;
12
+ this.started = false;
13
+ //There is only one connection for the entire pool
14
+ this.subscriber = null;
15
+ //The slot range for which this subscriber is responsible
16
+ this.slotRange = [];
17
+ this.onSubscriberEnd = () => {
18
+ if (!this.started) {
19
+ debug("subscriber has disconnected, but ClusterSubscriber is not started, so not reconnecting.");
20
+ return;
21
+ }
22
+ // If the subscriber closes whilst it's still the active connection,
23
+ // we might as well try to connecting to a new node if possible to
24
+ // minimise the number of missed publishes.
25
+ debug("subscriber has disconnected, selecting a new one...");
26
+ this.selectSubscriber();
27
+ };
28
+ // If the current node we're using as the subscriber disappears
29
+ // from the node pool for some reason, we will select a new one
30
+ // to connect to.
31
+ // Note that this event is only triggered if the connection to
32
+ // the node has been used; cluster subscriptions are setup with
33
+ // lazyConnect = true. It's possible for the subscriber node to
34
+ // disappear without this method being called!
35
+ // See https://github.com/luin/ioredis/pull/1589
36
+ this.connectionPool.on("-node", (_, key) => {
37
+ if (!this.started || !this.subscriber) {
38
+ return;
39
+ }
40
+ if ((0, util_1.getNodeKey)(this.subscriber.options) === key) {
41
+ debug("subscriber has left, selecting a new one...");
42
+ this.selectSubscriber();
43
+ }
44
+ });
45
+ this.connectionPool.on("+node", () => {
46
+ if (!this.started || this.subscriber) {
47
+ return;
48
+ }
49
+ debug("a new node is discovered and there is no subscriber, selecting a new one...");
50
+ this.selectSubscriber();
51
+ });
52
+ }
53
+ getInstance() {
54
+ return this.subscriber;
55
+ }
56
+ /**
57
+ * Associate this subscriber to a specific slot range.
58
+ *
59
+ * Returns the range or an empty array if the slot range couldn't be associated.
60
+ *
61
+ * BTW: This is more for debugging and testing purposes.
62
+ *
63
+ * @param range
64
+ */
65
+ associateSlotRange(range) {
66
+ if (this.isSharded) {
67
+ this.slotRange = range;
68
+ }
69
+ return this.slotRange;
70
+ }
71
+ start() {
72
+ this.started = true;
73
+ this.selectSubscriber();
74
+ debug("started");
75
+ }
76
+ stop() {
77
+ this.started = false;
78
+ if (this.subscriber) {
79
+ this.subscriber.disconnect();
80
+ this.subscriber = null;
81
+ }
82
+ }
83
+ isStarted() {
84
+ return this.started;
85
+ }
86
+ selectSubscriber() {
87
+ const lastActiveSubscriber = this.lastActiveSubscriber;
88
+ // Disconnect the previous subscriber even if there
89
+ // will not be a new one.
90
+ if (lastActiveSubscriber) {
91
+ lastActiveSubscriber.off("end", this.onSubscriberEnd);
92
+ lastActiveSubscriber.disconnect();
93
+ }
94
+ if (this.subscriber) {
95
+ this.subscriber.off("end", this.onSubscriberEnd);
96
+ this.subscriber.disconnect();
97
+ }
98
+ const sampleNode = (0, utils_1.sample)(this.connectionPool.getNodes());
99
+ if (!sampleNode) {
100
+ debug("selecting subscriber failed since there is no node discovered in the cluster yet");
101
+ this.subscriber = null;
102
+ return;
103
+ }
104
+ const { options } = sampleNode;
105
+ debug("selected a subscriber %s:%s", options.host, options.port);
106
+ /*
107
+ * Create a specialized Redis connection for the subscription.
108
+ * Note that auto reconnection is enabled here.
109
+ *
110
+ * `enableReadyCheck` is also enabled because although subscription is allowed
111
+ * while redis is loading data from the disk, we can check if the password
112
+ * provided for the subscriber is correct, and if not, the current subscriber
113
+ * will be disconnected and a new subscriber will be selected.
114
+ */
115
+ let connectionPrefix = "subscriber";
116
+ if (this.isSharded)
117
+ connectionPrefix = "ssubscriber";
118
+ this.subscriber = new Redis_1.default({
119
+ port: options.port,
120
+ host: options.host,
121
+ username: options.username,
122
+ password: options.password,
123
+ enableReadyCheck: true,
124
+ connectionName: (0, util_1.getConnectionName)(connectionPrefix, options.connectionName),
125
+ lazyConnect: true,
126
+ tls: options.tls,
127
+ // Don't try to reconnect the subscriber connection. If the connection fails
128
+ // we will get an end event (handled below), at which point we'll pick a new
129
+ // node from the pool and try to connect to that as the subscriber connection.
130
+ retryStrategy: null,
131
+ });
132
+ // Ignore the errors since they're handled in the connection pool.
133
+ this.subscriber.on("error", utils_1.noop);
134
+ this.subscriber.on("moved", () => {
135
+ this.emitter.emit("forceRefresh");
136
+ });
137
+ // The node we lost connection to may not come back up in a
138
+ // reasonable amount of time (e.g. a slave that's taken down
139
+ // for maintainence), we could potentially miss many published
140
+ // messages so we should reconnect as quickly as possible, to
141
+ // a different node if needed.
142
+ this.subscriber.once("end", this.onSubscriberEnd);
143
+ // Re-subscribe previous channels
144
+ const previousChannels = { subscribe: [], psubscribe: [], ssubscribe: [] };
145
+ if (lastActiveSubscriber) {
146
+ const condition = lastActiveSubscriber.condition || lastActiveSubscriber.prevCondition;
147
+ if (condition && condition.subscriber) {
148
+ previousChannels.subscribe = condition.subscriber.channels("subscribe");
149
+ previousChannels.psubscribe =
150
+ condition.subscriber.channels("psubscribe");
151
+ previousChannels.ssubscribe =
152
+ condition.subscriber.channels("ssubscribe");
153
+ }
154
+ }
155
+ if (previousChannels.subscribe.length ||
156
+ previousChannels.psubscribe.length ||
157
+ previousChannels.ssubscribe.length) {
158
+ let pending = 0;
159
+ for (const type of ["subscribe", "psubscribe", "ssubscribe"]) {
160
+ const channels = previousChannels[type];
161
+ if (channels.length == 0) {
162
+ continue;
163
+ }
164
+ debug("%s %d channels", type, channels.length);
165
+ if (type === "ssubscribe") {
166
+ for (const channel of channels) {
167
+ pending += 1;
168
+ this.subscriber[type](channel)
169
+ .then(() => {
170
+ if (!--pending) {
171
+ this.lastActiveSubscriber = this.subscriber;
172
+ }
173
+ })
174
+ .catch(() => {
175
+ // TODO: should probably disconnect the subscriber and try again.
176
+ debug("failed to ssubscribe to channel: %s", channel);
177
+ });
178
+ }
179
+ }
180
+ else {
181
+ pending += 1;
182
+ this.subscriber[type](channels)
183
+ .then(() => {
184
+ if (!--pending) {
185
+ this.lastActiveSubscriber = this.subscriber;
186
+ }
187
+ })
188
+ .catch(() => {
189
+ // TODO: should probably disconnect the subscriber and try again.
190
+ debug("failed to %s %d channels", type, channels.length);
191
+ });
192
+ }
193
+ }
194
+ }
195
+ else {
196
+ this.lastActiveSubscriber = this.subscriber;
197
+ }
198
+ for (const event of [
199
+ "message",
200
+ "messageBuffer",
201
+ ]) {
202
+ this.subscriber.on(event, (arg1, arg2) => {
203
+ this.emitter.emit(event, arg1, arg2);
204
+ });
205
+ }
206
+ for (const event of ["pmessage", "pmessageBuffer"]) {
207
+ this.subscriber.on(event, (arg1, arg2, arg3) => {
208
+ this.emitter.emit(event, arg1, arg2, arg3);
209
+ });
210
+ }
211
+ if (this.isSharded == true) {
212
+ for (const event of [
213
+ "smessage",
214
+ "smessageBuffer",
215
+ ]) {
216
+ this.subscriber.on(event, (arg1, arg2) => {
217
+ this.emitter.emit(event, arg1, arg2);
218
+ });
219
+ }
220
+ }
221
+ }
222
+ }
223
+ exports.default = ClusterSubscriber;
@@ -0,0 +1,108 @@
1
+ /// <reference types="node" />
2
+ import * as EventEmitter from "events";
3
+ import ShardedSubscriber from "./ShardedSubscriber";
4
+ import { ClusterOptions } from "./ClusterOptions";
5
+ /**
6
+ * Redis distinguishes between "normal" and sharded PubSub. When using the normal PubSub feature,
7
+ * exactly one subscriber exists per cluster instance because the Redis cluster bus forwards
8
+ * messages between shards. Sharded PubSub removes this limitation by making each shard
9
+ * responsible for its own messages.
10
+ *
11
+ * This class coordinates one ShardedSubscriber per master node in the cluster, providing
12
+ * sharded PubSub support while keeping the public API backward compatible.
13
+ */
14
+ export default class ClusterSubscriberGroup {
15
+ private readonly subscriberGroupEmitter;
16
+ private readonly options;
17
+ private shardedSubscribers;
18
+ private clusterSlots;
19
+ private subscriberToSlotsIndex;
20
+ private channels;
21
+ private failedAttemptsByNode;
22
+ private isResetting;
23
+ private pendingReset;
24
+ private static readonly MAX_RETRY_ATTEMPTS;
25
+ private static readonly MAX_BACKOFF_MS;
26
+ private static readonly BASE_BACKOFF_MS;
27
+ /**
28
+ * Register callbacks
29
+ *
30
+ * @param cluster
31
+ */
32
+ constructor(subscriberGroupEmitter: EventEmitter, options: ClusterOptions);
33
+ /**
34
+ * Get the responsible subscriber.
35
+ *
36
+ * @param slot
37
+ */
38
+ getResponsibleSubscriber(slot: number): ShardedSubscriber | undefined;
39
+ /**
40
+ * Adds a channel for which this subscriber group is responsible
41
+ *
42
+ * @param channels
43
+ */
44
+ addChannels(channels: (string | Buffer)[]): number;
45
+ /**
46
+ * Removes channels for which the subscriber group is responsible by optionally unsubscribing
47
+ * @param channels
48
+ */
49
+ removeChannels(channels: (string | Buffer)[]): number;
50
+ /**
51
+ * Disconnect all subscribers and clear some of the internal state.
52
+ */
53
+ stop(): void;
54
+ /**
55
+ * Start all not yet started subscribers
56
+ */
57
+ start(): Promise<any[]>;
58
+ /**
59
+ * Resets the subscriber group by disconnecting all subscribers that are no longer needed and connecting new ones.
60
+ */
61
+ reset(clusterSlots: string[][], clusterNodes: any[]): Promise<void>;
62
+ /**
63
+ * Refreshes the subscriber-related slot ranges
64
+ *
65
+ * Returns false if no refresh was needed
66
+ *
67
+ * @param targetSlots
68
+ */
69
+ private _refreshSlots;
70
+ /**
71
+ * Resubscribes to the previous channels
72
+ *
73
+ * @private
74
+ */
75
+ private _resubscribe;
76
+ /**
77
+ * Deep equality of the cluster slots objects
78
+ *
79
+ * @param other
80
+ * @private
81
+ */
82
+ private _slotsAreEqual;
83
+ /**
84
+ * Checks if any subscribers are in an unhealthy state.
85
+ *
86
+ * A subscriber is considered unhealthy if:
87
+ * - It exists but is not started (failed/disconnected)
88
+ * - It's missing entirely for a node that should have one
89
+ *
90
+ * @returns true if any subscribers need to be recreated
91
+ */
92
+ private hasUnhealthySubscribers;
93
+ /**
94
+ * Handles failed subscriber connections by emitting an event to refresh the slots cache
95
+ * after a backoff period.
96
+ *
97
+ * @param error
98
+ * @param nodeKey
99
+ */
100
+ private handleSubscriberConnectFailed;
101
+ /**
102
+ * Handles successful subscriber connections by resetting the failed attempts counter.
103
+ *
104
+ * @param nodeKey
105
+ */
106
+ private handleSubscriberConnectSucceeded;
107
+ private shouldStartSubscriber;
108
+ }