@jetit/publisher 1.1.3 → 1.3.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 +1 -1
- package/src/lib/redis/streams.js +53 -36
package/package.json
CHANGED
package/src/lib/redis/streams.js
CHANGED
|
@@ -43,16 +43,17 @@ class Streams {
|
|
|
43
43
|
var _a;
|
|
44
44
|
this.eventsListened = [];
|
|
45
45
|
this.instanceId = `${serviceName}:${(0, id_1.generateID)('HEX', 'FE')}`;
|
|
46
|
+
console.log(this.instanceId);
|
|
46
47
|
this.consumerGroupName = `cg-${serviceName}`;
|
|
47
48
|
const cleanUpInterval = (_a = parseInt(process.env['CLEANUP_INTERVAL'] || `${1000 * 60 * 60}`, 10)) !== null && _a !== void 0 ? _a : 1000 * 60 * 60;
|
|
48
|
-
setTimeout(() => this.runClear(cleanUpInterval),
|
|
49
|
+
setTimeout(() => this.runClear(cleanUpInterval), 60000);
|
|
49
50
|
this.cleanUpTimer = setInterval(() => {
|
|
50
51
|
this.runClear(cleanUpInterval);
|
|
51
52
|
}, cleanUpInterval);
|
|
52
53
|
}
|
|
53
54
|
runClear(cleanUpInterval) {
|
|
54
55
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
55
|
-
console.log('Running Publisher Clearance');
|
|
56
|
+
console.log('Running Publisher Clearance', this.eventsListened);
|
|
56
57
|
this.clearDuplicationCheckKeys();
|
|
57
58
|
for (const eventName of this.eventsListened) {
|
|
58
59
|
process.nextTick(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -271,23 +272,25 @@ class Streams {
|
|
|
271
272
|
*/
|
|
272
273
|
republishUnprocessedEvents(eventName) {
|
|
273
274
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
275
|
+
console.log('Republishing Unprocessed Events.');
|
|
274
276
|
const streamName = `${eventName}:${this.consumerGroupName}`;
|
|
275
277
|
const result = yield this.redisGroups.xreadgroup('GROUP', this.consumerGroupName, this.instanceId, 'STREAMS', streamName, '>');
|
|
276
|
-
if (result)
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
278
|
+
if (!result)
|
|
279
|
+
return;
|
|
280
|
+
const [, streamMessages] = result[0];
|
|
281
|
+
if (!streamMessages)
|
|
282
|
+
return;
|
|
283
|
+
console.log(`Unprocessed events: ${streamMessages.length}`);
|
|
284
|
+
for (const [id, data] of streamMessages) {
|
|
285
|
+
const transaction = this.redisGroups.multi({ pipeline: true });
|
|
286
|
+
const eventData = JSON.parse(data[1]);
|
|
287
|
+
// Republishing the events
|
|
288
|
+
transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
|
|
289
|
+
transaction.publish(eventName, '');
|
|
290
|
+
transaction.xack(streamName, this.consumerGroupName, id);
|
|
291
|
+
yield transaction.exec().catch(publisherErrorHandler);
|
|
292
|
+
console.log(`Event ${eventName} with ID: ${id} published`);
|
|
293
|
+
yield transaction.exec();
|
|
291
294
|
}
|
|
292
295
|
});
|
|
293
296
|
}
|
|
@@ -307,6 +310,7 @@ class Streams {
|
|
|
307
310
|
*/
|
|
308
311
|
recoverCrashedConsumerMessages(eventName, idleTimeout = 30000) {
|
|
309
312
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
console.log(`PUBLISHER: Running recoverCrashedConsumerMessages`);
|
|
310
314
|
const streamName = `${eventName}:${this.consumerGroupName}`;
|
|
311
315
|
const pendingMessages = (yield this.redisGroups.xpending(streamName, this.consumerGroupName));
|
|
312
316
|
if (!pendingMessages)
|
|
@@ -315,19 +319,22 @@ class Streams {
|
|
|
315
319
|
if (!consumers || consumers.length === 0)
|
|
316
320
|
return;
|
|
317
321
|
for (const [consumer, pendingCount] of consumers) {
|
|
318
|
-
if (parseInt(pendingCount)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
322
|
+
if (parseInt(pendingCount) < 0)
|
|
323
|
+
return;
|
|
324
|
+
const pending = (yield this.redisGroups.xpending(streamName, this.consumerGroupName, minId, maxId, Number(pendingCount), consumer));
|
|
325
|
+
if (!pending)
|
|
326
|
+
return;
|
|
327
|
+
for (const [messageId] of pending) {
|
|
328
|
+
const claimedMessage = (yield this.redisGroups.xclaim(streamName, this.consumerGroupName, this.instanceId, idleTimeout, messageId));
|
|
329
|
+
if (claimedMessage) {
|
|
330
|
+
console.log({ claimedMessage: JSON.stringify(claimedMessage) });
|
|
331
|
+
const [, data] = claimedMessage[0];
|
|
332
|
+
const eventData = JSON.parse(data[1]);
|
|
333
|
+
const transaction = this.redisGroups.multi();
|
|
334
|
+
transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
|
|
335
|
+
transaction.publish(eventName, '');
|
|
336
|
+
transaction.xack(streamName, this.consumerGroupName, messageId);
|
|
337
|
+
yield transaction.exec().catch(publisherErrorHandler);
|
|
331
338
|
}
|
|
332
339
|
}
|
|
333
340
|
}
|
|
@@ -355,7 +362,7 @@ class Streams {
|
|
|
355
362
|
*/
|
|
356
363
|
close() {
|
|
357
364
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
358
|
-
this.clearSubscribedEvents();
|
|
365
|
+
yield this.clearSubscribedEvents();
|
|
359
366
|
if (this.redisPublisher) {
|
|
360
367
|
yield this.redisPublisher.quit();
|
|
361
368
|
}
|
|
@@ -373,11 +380,17 @@ class Streams {
|
|
|
373
380
|
clearSubscribedEvents() {
|
|
374
381
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
375
382
|
console.log(`${this.eventsListened.length} events to be cleared`);
|
|
383
|
+
let x = this.eventsListened.length;
|
|
376
384
|
for (const eventName of this.eventsListened) {
|
|
385
|
+
console.log(`${eventName} is being cleared in publisher`);
|
|
377
386
|
yield this.redisGroups.srem(`${eventName}`, this.consumerGroupName);
|
|
387
|
+
console.log(`${eventName} is removed from ${this.consumerGroupName}`);
|
|
378
388
|
// Releasing all claims based on info from: https://redis.io/commands/xgroup-delconsumer/
|
|
379
389
|
yield this.releaseAllClaims(eventName);
|
|
390
|
+
console.log(`${eventName} removes all claims`);
|
|
380
391
|
yield this.redisGroups.xgroup('DELCONSUMER', eventName, this.consumerGroupName, this.instanceId);
|
|
392
|
+
console.log(`${eventName} is deleted as a consumer from ${this.consumerGroupName}, ${this.instanceId}`);
|
|
393
|
+
console.log(x--);
|
|
381
394
|
}
|
|
382
395
|
});
|
|
383
396
|
}
|
|
@@ -388,14 +401,18 @@ class Streams {
|
|
|
388
401
|
}
|
|
389
402
|
releaseAllClaims(eventName) {
|
|
390
403
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
391
|
-
|
|
392
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Retrieve the pending messages for the consumer. Note this only fetches the last
|
|
406
|
+
* 10000 events assigned to this consumer. This function has been modified to make sure
|
|
407
|
+
* that there is a temp instance that claims all this messages
|
|
408
|
+
*/
|
|
409
|
+
const pendingMessages = (yield this.redisGroups.xpending(eventName, this.consumerGroupName, '-', '+', 10000, this.instanceId));
|
|
393
410
|
if (pendingMessages && pendingMessages.length > 0) {
|
|
411
|
+
console.log(`${pendingMessages.length} messages to clean up.`);
|
|
394
412
|
const transaction = this.redisGroups.multi({ pipeline: true });
|
|
413
|
+
const tempConsumerId = `${this.instanceId}-temp`;
|
|
395
414
|
for (const [messageId] of pendingMessages) {
|
|
396
|
-
|
|
397
|
-
const idleTime = 10000;
|
|
398
|
-
transaction.xclaim(eventName, this.consumerGroupName, this.instanceId, idleTime);
|
|
415
|
+
transaction.xclaim(eventName, this.consumerGroupName, tempConsumerId, 10, messageId);
|
|
399
416
|
}
|
|
400
417
|
yield transaction.exec();
|
|
401
418
|
}
|