@jetit/publisher 1.7.2 → 2.0.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/package.json
CHANGED
|
@@ -4,7 +4,7 @@ export type RedisType = Redis | Cluster;
|
|
|
4
4
|
export declare class RedisRegistry {
|
|
5
5
|
private static registry;
|
|
6
6
|
private static options;
|
|
7
|
-
static attemptConnection(connectionKey: string, storeRef?: number):
|
|
7
|
+
static attemptConnection(connectionKey: string, storeRef?: number): RedisType;
|
|
8
8
|
static getConnection(connectionType?: string, storeRef?: number): RedisType;
|
|
9
9
|
static setOptions(options: IOptions): void;
|
|
10
10
|
static _getOptions(): IOptions;
|
|
@@ -7,11 +7,10 @@ class RedisRegistry {
|
|
|
7
7
|
static attemptConnection(connectionKey, storeRef = 0) {
|
|
8
8
|
let ref;
|
|
9
9
|
if (RedisRegistry.options.cluster) {
|
|
10
|
-
ref = new ioredis_1.Cluster(RedisRegistry.options.cluster.nodes, Object.assign(Object.assign({}, RedisRegistry.options.cluster.options), { redisOptions: {
|
|
11
|
-
db: storeRef,
|
|
12
|
-
} }));
|
|
10
|
+
ref = new ioredis_1.Cluster(RedisRegistry.options.cluster.nodes, Object.assign(Object.assign({}, RedisRegistry.options.cluster.options), { redisOptions: Object.assign(Object.assign({}, RedisRegistry.options.cluster.options.redisOptions), { db: storeRef }) }));
|
|
13
11
|
}
|
|
14
|
-
|
|
12
|
+
else
|
|
13
|
+
ref = new ioredis_1.default(Object.assign(Object.assign({}, RedisRegistry.options.redis), { db: storeRef }));
|
|
15
14
|
RedisRegistry.registry.set(connectionKey, ref);
|
|
16
15
|
return ref;
|
|
17
16
|
}
|
|
@@ -20,11 +19,10 @@ class RedisRegistry {
|
|
|
20
19
|
let ref = this.registry.get(connectionKey);
|
|
21
20
|
if (!ref) {
|
|
22
21
|
if (RedisRegistry.options.cluster) {
|
|
23
|
-
ref = new ioredis_1.Cluster(RedisRegistry.options.cluster.nodes, Object.assign(Object.assign({}, RedisRegistry.options.cluster.options), { redisOptions: {
|
|
24
|
-
db: storeRef,
|
|
25
|
-
} }));
|
|
22
|
+
ref = new ioredis_1.Cluster(RedisRegistry.options.cluster.nodes, Object.assign(Object.assign({}, RedisRegistry.options.cluster.options), { redisOptions: Object.assign(Object.assign({}, RedisRegistry.options.cluster.options.redisOptions), { db: storeRef }) }));
|
|
26
23
|
}
|
|
27
|
-
|
|
24
|
+
else
|
|
25
|
+
ref = new ioredis_1.default(Object.assign(Object.assign({}, RedisRegistry.options.redis), { db: storeRef }));
|
|
28
26
|
}
|
|
29
27
|
return ref;
|
|
30
28
|
}
|
|
@@ -51,23 +51,21 @@ class ScheduledProcessor {
|
|
|
51
51
|
* Instead of using the publish method directly, the entire logic is
|
|
52
52
|
* copy pasted to reduce the case of failure.
|
|
53
53
|
*/
|
|
54
|
-
const transaction = this.redisPublisher.multi({ pipeline: true });
|
|
55
54
|
eventData.eventId = (0, id_1.generateID)('HEX', 'FF');
|
|
56
|
-
|
|
55
|
+
yield this.redisPublisher.zrem('se', eventString);
|
|
57
56
|
const consumerGroups = yield (0, groups_1.getAllConsumerGroups)(eventData.eventName, this.redisPublisher);
|
|
58
57
|
console.log('Scheduled Publishing to consumer groups: ', consumerGroups, 'with id ', eventData.eventId, '...');
|
|
59
58
|
for (const consumerGroup of consumerGroups) {
|
|
60
59
|
// Publish the event to each consumer group's stream
|
|
61
60
|
const streamName = `${eventData.eventName}:${consumerGroup}`;
|
|
62
|
-
|
|
61
|
+
yield this.redisPublisher.xadd(streamName, '*', 'data', JSON.stringify(eventData));
|
|
63
62
|
}
|
|
64
63
|
if (eventData.repeatInterval) {
|
|
65
64
|
const nextEventTime = currentTime + eventData.repeatInterval;
|
|
66
65
|
const nextEventString = JSON.stringify(Object.assign({}, eventData));
|
|
67
|
-
|
|
66
|
+
yield this.redisPublisher.zadd('se', nextEventTime, nextEventString);
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
yield transaction.exec();
|
|
68
|
+
yield this.redisPublisher.publish(eventData.eventName, '');
|
|
71
69
|
}
|
|
72
70
|
});
|
|
73
71
|
}
|
package/src/lib/redis/streams.js
CHANGED
|
@@ -82,16 +82,14 @@ class Streams {
|
|
|
82
82
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
83
83
|
const processedMessagesKeyPattern = `pm:${this.consumerGroupName}:*`;
|
|
84
84
|
let cursor = '0';
|
|
85
|
-
const transaction = this.redisGroups.pipeline();
|
|
86
85
|
do {
|
|
87
86
|
const [nextCursor, keys] = yield this.redisGroups.scan(cursor, 'MATCH', processedMessagesKeyPattern);
|
|
88
87
|
cursor = nextCursor;
|
|
89
88
|
for (const key of keys) {
|
|
90
89
|
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
91
|
-
|
|
90
|
+
yield this.redisGroups.zremrangebyscore(key, '-inf', oneHourAgo);
|
|
92
91
|
}
|
|
93
92
|
} while (cursor !== '0');
|
|
94
|
-
yield transaction.exec();
|
|
95
93
|
});
|
|
96
94
|
}
|
|
97
95
|
publish(data) {
|
|
@@ -101,20 +99,21 @@ class Streams {
|
|
|
101
99
|
data.eventId = (0, id_1.generateID)('HEX', 'FF');
|
|
102
100
|
if (!data.createdAt)
|
|
103
101
|
data.createdAt = Date.now();
|
|
104
|
-
const transaction = this.redisPublisher.multi({ pipeline: true });
|
|
105
102
|
const consumerGroups = yield (0, groups_1.getAllConsumerGroups)(data.eventName, this.redisPublisher);
|
|
106
103
|
if (consumerGroups.length > 0) {
|
|
107
104
|
console.log(`PUBLISHER: Publishing event ${data.eventName} to consumer groups: ${consumerGroups.join(', ')}`);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
try {
|
|
106
|
+
for (const consumerGroup of consumerGroups) {
|
|
107
|
+
// Publish the event to each consumer group's stream
|
|
108
|
+
const streamName = `${data.eventName}:${consumerGroup}`;
|
|
109
|
+
yield this.redisPublisher.xadd(streamName, '*', 'data', JSON.stringify(data));
|
|
110
|
+
}
|
|
111
|
+
yield this.redisPublisher.publish(data.eventName, '');
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
yield transaction.exec().catch((error) => {
|
|
113
|
+
catch (error) {
|
|
115
114
|
console.error(`PUBLISHER: Error while publishing event for service ${this.consumerGroupName} with instance ${this.instanceId}: `, error);
|
|
116
115
|
throw new Error('Publisher Error');
|
|
117
|
-
}
|
|
116
|
+
}
|
|
118
117
|
}
|
|
119
118
|
else
|
|
120
119
|
console.log(`PUBLISHER: Event publish failed for event ${data.eventName}, reason: no consumers ${consumerGroups}`);
|
|
@@ -187,19 +186,24 @@ class Streams {
|
|
|
187
186
|
}
|
|
188
187
|
createConsumerAndRegister(eventName) {
|
|
189
188
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
190
|
-
const pipeline = this.redisGroups.multi();
|
|
191
189
|
const streamName = `${eventName}:${this.consumerGroupName}`;
|
|
192
190
|
const key = `instance:${this.instanceId}:subscribedEvents`;
|
|
193
191
|
const setKeyForK8sHandling = `instance:${this.instanceUniqueId}:consumerGroupName`;
|
|
194
192
|
this.eventsListened.push(eventName);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
193
|
+
yield this.redisGroups
|
|
194
|
+
.xgroup('CREATE', streamName, this.consumerGroupName, '0', 'MKSTREAM')
|
|
195
|
+
.then((v) => {
|
|
196
|
+
console.log(`Group created created for ${JSON.stringify({ streamName, cgn: this.consumerGroupName })}`);
|
|
197
|
+
})
|
|
198
|
+
.catch((e) => {
|
|
199
|
+
console.log(`Group creation failed with error ${e.message} for ${JSON.stringify({ streamName, cgn: this.consumerGroupName })}`);
|
|
200
|
+
});
|
|
201
|
+
const createConsumerStatus = (yield this.redisGroups.xgroup('CREATECONSUMER', streamName, this.consumerGroupName, this.instanceId));
|
|
202
|
+
yield this.redisGroups.sadd(key, eventName);
|
|
203
|
+
const addToCGSet = yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
|
|
204
|
+
const addToFlushSet = yield this.redisGroups.set(setKeyForK8sHandling, this.consumerGroupName);
|
|
205
|
+
console.log(`PUBLISHER: Consumer Registered and created with ${this.instanceId} under ${this.consumerGroupName} with ${createConsumerStatus} consumers and with the following status ${JSON.stringify({ addToCGSet, addToFlushSet })}`);
|
|
206
|
+
return createConsumerStatus === 0 || createConsumerStatus === 1;
|
|
203
207
|
});
|
|
204
208
|
}
|
|
205
209
|
listenInternals(eventName) {
|
|
@@ -237,11 +241,9 @@ class Streams {
|
|
|
237
241
|
bs.next(eventData);
|
|
238
242
|
const pmKey = `pm:${this.consumerGroupName}:${streamName}`;
|
|
239
243
|
const currentTime = Date.now();
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
transaction.zadd(`ack:${streamName}`, Date.now(), id);
|
|
244
|
-
yield transaction.exec();
|
|
244
|
+
yield redisClient.zadd(pmKey, currentTime, messageId);
|
|
245
|
+
yield redisClient.xack(streamName, this.consumerGroupName, id);
|
|
246
|
+
yield redisClient.zadd(`ack:${streamName}`, Date.now(), id);
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
this.scanAndClaimAUnclaimedMessage(streamName)
|
|
@@ -333,14 +335,12 @@ class Streams {
|
|
|
333
335
|
const cleanupThreshold = Date.now() - interval;
|
|
334
336
|
const acknowledgedMessages = yield this.redisGroups.zrangebyscore(`ack:${streamName}`, '-inf', cleanupThreshold);
|
|
335
337
|
if (acknowledgedMessages && acknowledgedMessages.length > 0) {
|
|
336
|
-
const transaction = this.redisGroups.pipeline();
|
|
337
338
|
// Remove acknowledged messages from the stream
|
|
338
339
|
for (const messageId of acknowledgedMessages) {
|
|
339
|
-
|
|
340
|
+
yield this.redisGroups.xdel(streamName, messageId);
|
|
340
341
|
}
|
|
341
342
|
// Remove acknowledged messages from the Sorted Set
|
|
342
|
-
|
|
343
|
-
yield transaction.exec();
|
|
343
|
+
yield this.redisGroups.zremrangebyscore(`ack:${streamName}`, '-inf', cleanupThreshold);
|
|
344
344
|
}
|
|
345
345
|
});
|
|
346
346
|
}
|