@jetit/publisher 1.1.2 → 1.2.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetit/publisher",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "@jetit/id": "0.0.11",
@@ -149,5 +149,6 @@ export declare class Streams {
149
149
  close(): Promise<void>;
150
150
  private clearSubscribedEvents;
151
151
  private registerConsumerGroup;
152
+ releaseAllClaims(eventName: string): Promise<void>;
152
153
  private cleanupAcknowledgedMessages;
153
154
  }
@@ -43,6 +43,7 @@ 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
49
  setTimeout(() => this.runClear(cleanUpInterval), 3000);
@@ -52,7 +53,7 @@ class Streams {
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* () {
@@ -277,17 +278,18 @@ class Streams {
277
278
  const [, streamMessages] = result[0];
278
279
  if (!streamMessages)
279
280
  return;
280
- console.log(`Unprocessed events: ${streamMessages.length}`);
281
- const transaction = this.redisGroups.multi({ pipeline: true });
281
+ console.log(`Unprocessed events: ${streamMessages.length}`);
282
282
  for (const [id, data] of streamMessages) {
283
+ const transaction = this.redisGroups.multi({ pipeline: true });
283
284
  const eventData = JSON.parse(data[1]);
284
285
  // Republishing the events
285
286
  transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
286
287
  transaction.publish(eventName, '');
287
288
  transaction.xack(streamName, this.consumerGroupName, id);
289
+ yield transaction.exec().catch(publisherErrorHandler);
288
290
  console.log(`Event ${eventName} with ID: ${id} published`);
291
+ yield transaction.exec();
289
292
  }
290
- yield transaction.exec();
291
293
  }
292
294
  });
293
295
  }
@@ -314,23 +316,26 @@ class Streams {
314
316
  const [, minId, maxId, consumers] = pendingMessages;
315
317
  if (!consumers || consumers.length === 0)
316
318
  return;
317
- const transaction = this.redisGroups.multi({ pipeline: true });
318
319
  for (const [consumer, pendingCount] of consumers) {
320
+ const transaction = this.redisGroups.multi({ pipeline: true });
319
321
  if (parseInt(pendingCount) > 0) {
320
322
  const pending = (yield this.redisGroups.xpending(streamName, this.consumerGroupName, minId, maxId, Number(pendingCount), consumer));
321
323
  for (const [messageId] of pending) {
322
324
  const claimedMessage = (yield this.redisGroups.xclaim(streamName, this.consumerGroupName, this.instanceId, idleTimeout, messageId));
323
325
  if (claimedMessage) {
326
+ console.log({ claimedMessage: JSON.stringify(claimedMessage) });
324
327
  const [, data] = claimedMessage[0];
325
328
  const eventData = JSON.parse(data[1]);
329
+ const transaction = this.redisGroups.multi();
326
330
  transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
327
331
  transaction.publish(eventName, '');
328
332
  transaction.xack(streamName, this.consumerGroupName, messageId);
333
+ yield transaction.exec().catch(publisherErrorHandler);
329
334
  }
330
335
  }
331
336
  }
337
+ yield transaction.exec();
332
338
  }
333
- yield transaction.exec();
334
339
  });
335
340
  }
336
341
  /**
@@ -355,7 +360,7 @@ class Streams {
355
360
  */
356
361
  close() {
357
362
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
358
- this.clearSubscribedEvents();
363
+ yield this.clearSubscribedEvents();
359
364
  if (this.redisPublisher) {
360
365
  yield this.redisPublisher.quit();
361
366
  }
@@ -373,8 +378,17 @@ class Streams {
373
378
  clearSubscribedEvents() {
374
379
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
375
380
  console.log(`${this.eventsListened.length} events to be cleared`);
381
+ let x = this.eventsListened.length;
376
382
  for (const eventName of this.eventsListened) {
383
+ console.log(`${eventName} is being cleared in publisher`);
377
384
  yield this.redisGroups.srem(`${eventName}`, this.consumerGroupName);
385
+ console.log(`${eventName} is removed from ${this.consumerGroupName}`);
386
+ // Releasing all claims based on info from: https://redis.io/commands/xgroup-delconsumer/
387
+ yield this.releaseAllClaims(eventName);
388
+ console.log(`${eventName} removes all claims`);
389
+ yield this.redisGroups.xgroup('DELCONSUMER', eventName, this.consumerGroupName, this.instanceId);
390
+ console.log(`${eventName} is deleted as a consumer from ${this.consumerGroupName}, ${this.instanceId}`);
391
+ console.log(x--);
378
392
  }
379
393
  });
380
394
  }
@@ -383,13 +397,32 @@ class Streams {
383
397
  yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
384
398
  });
385
399
  }
400
+ releaseAllClaims(eventName) {
401
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
402
+ /**
403
+ * Retrieve the pending messages for the consumer. Note this only fetches the last
404
+ * 10000 events assigned to this consumer. This function has been modified to make sure
405
+ * that there is a temp instance that claims all this messages
406
+ */
407
+ const pendingMessages = (yield this.redisGroups.xpending(eventName, this.consumerGroupName, '-', '+', 10000, this.instanceId));
408
+ if (pendingMessages && pendingMessages.length > 0) {
409
+ console.log(`${pendingMessages.length} messages to clean up.`);
410
+ const transaction = this.redisGroups.multi({ pipeline: true });
411
+ const tempConsumerId = `${this.instanceId}-temp`;
412
+ for (const [messageId] of pendingMessages) {
413
+ transaction.xclaim(eventName, this.consumerGroupName, tempConsumerId, 10, messageId);
414
+ }
415
+ yield transaction.exec();
416
+ }
417
+ });
418
+ }
386
419
  cleanupAcknowledgedMessages(eventName, interval = 60 * 60 * 1000) {
387
420
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
388
421
  const streamName = `${eventName}:${this.consumerGroupName}`;
389
422
  const cleanupThreshold = Date.now() - interval;
390
423
  const acknowledgedMessages = yield this.redisGroups.zrangebyscore(`ack:${streamName}`, '-inf', cleanupThreshold);
391
424
  if (acknowledgedMessages && acknowledgedMessages.length > 0) {
392
- const transaction = this.redisGroups.multi({ pipeline: true });
425
+ const transaction = this.redisGroups.pipeline();
393
426
  // Remove acknowledged messages from the stream
394
427
  for (const messageId of acknowledgedMessages) {
395
428
  transaction.xdel(streamName, messageId);