@jetit/publisher 1.2.0 → 1.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetit/publisher",
3
- "version": "1.2.0",
3
+ "version": "1.3.2",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "@jetit/id": "0.0.11",
@@ -7,6 +7,7 @@ export declare class Streams {
7
7
  private _redisGroups?;
8
8
  private consumerGroupName;
9
9
  private instanceId;
10
+ private instanceUniqueId;
10
11
  private cleanUpTimer;
11
12
  private eventsListened;
12
13
  get redisPublisher(): RedisType;
@@ -148,7 +149,9 @@ export declare class Streams {
148
149
  */
149
150
  close(): Promise<void>;
150
151
  private clearSubscribedEvents;
152
+ private registerSubscribedEvent;
151
153
  private registerConsumerGroup;
152
- releaseAllClaims(eventName: string): Promise<void>;
154
+ private registerConsumerGroupName;
155
+ releaseAllClaims(streamName: string): Promise<void>;
153
156
  private cleanupAcknowledgedMessages;
154
157
  }
@@ -40,13 +40,14 @@ class Streams {
40
40
  * const streams = new Streams('POS');
41
41
  */
42
42
  constructor(serviceName) {
43
- var _a;
43
+ var _a, _b;
44
44
  this.eventsListened = [];
45
- this.instanceId = `${serviceName}:${(0, id_1.generateID)('HEX', 'FE')}`;
45
+ this.instanceUniqueId = (_a = process.env['INSTANCE_ID']) !== null && _a !== void 0 ? _a : (0, id_1.generateID)('HEX', 'FE');
46
+ this.instanceId = `${serviceName}:${this.instanceUniqueId}`;
46
47
  console.log(this.instanceId);
47
48
  this.consumerGroupName = `cg-${serviceName}`;
48
- const cleanUpInterval = (_a = parseInt(process.env['CLEANUP_INTERVAL'] || `${1000 * 60 * 60}`, 10)) !== null && _a !== void 0 ? _a : 1000 * 60 * 60;
49
- setTimeout(() => this.runClear(cleanUpInterval), 3000);
49
+ const cleanUpInterval = (_b = parseInt(process.env['CLEANUP_INTERVAL'] || `${1000 * 60 * 60}`, 10)) !== null && _b !== void 0 ? _b : 1000 * 60 * 60;
50
+ setTimeout(() => this.runClear(cleanUpInterval), 60000);
50
51
  this.cleanUpTimer = setInterval(() => {
51
52
  this.runClear(cleanUpInterval);
52
53
  }, cleanUpInterval);
@@ -199,6 +200,7 @@ class Streams {
199
200
  */
200
201
  listen(eventName, maxRetries = 5, initialDelay = 1000) {
201
202
  this.registerConsumerGroup(eventName); // Registers the consumer group for listening to the message
203
+ this.registerConsumerGroupName().then();
202
204
  this.eventsListened.push(eventName);
203
205
  return this.listenInternals(eventName).pipe((0, rxjs_1.retry)({
204
206
  count: maxRetries,
@@ -214,7 +216,8 @@ class Streams {
214
216
  }
215
217
  listenInternals(eventName) {
216
218
  try {
217
- this.createConsumerGroup(eventName);
219
+ this.createConsumerGroup(eventName).then();
220
+ this.registerSubscribedEvent(eventName).then();
218
221
  const bs = new rxjs_1.BehaviorSubject(null);
219
222
  const observable = bs.asObservable().pipe((0, rxjs_1.skip)(1));
220
223
  const streamName = `${eventName}:${this.consumerGroupName}`;
@@ -272,24 +275,25 @@ class Streams {
272
275
  */
273
276
  republishUnprocessedEvents(eventName) {
274
277
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
278
+ console.log('Republishing Unprocessed Events.');
275
279
  const streamName = `${eventName}:${this.consumerGroupName}`;
276
280
  const result = yield this.redisGroups.xreadgroup('GROUP', this.consumerGroupName, this.instanceId, 'STREAMS', streamName, '>');
277
- if (result) {
278
- const [, streamMessages] = result[0];
279
- if (!streamMessages)
280
- return;
281
- console.log(`Unprocessed events: ${streamMessages.length}`);
282
- for (const [id, data] of streamMessages) {
283
- const transaction = this.redisGroups.multi({ pipeline: true });
284
- const eventData = JSON.parse(data[1]);
285
- // Republishing the events
286
- transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
287
- transaction.publish(eventName, '');
288
- transaction.xack(streamName, this.consumerGroupName, id);
289
- yield transaction.exec().catch(publisherErrorHandler);
290
- console.log(`Event ${eventName} with ID: ${id} published`);
291
- yield transaction.exec();
292
- }
281
+ if (!result)
282
+ return;
283
+ const [, streamMessages] = result[0];
284
+ if (!streamMessages)
285
+ return;
286
+ console.log(`Unprocessed events: ${streamMessages.length}`);
287
+ for (const [id, data] of streamMessages) {
288
+ const transaction = this.redisGroups.multi({ pipeline: true });
289
+ const eventData = JSON.parse(data[1]);
290
+ // Republishing the events
291
+ transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
292
+ transaction.publish(eventName, '');
293
+ transaction.xack(streamName, this.consumerGroupName, id);
294
+ yield transaction.exec().catch(publisherErrorHandler);
295
+ console.log(`Event ${eventName} with ID: ${id} published`);
296
+ yield transaction.exec();
293
297
  }
294
298
  });
295
299
  }
@@ -309,6 +313,7 @@ class Streams {
309
313
  */
310
314
  recoverCrashedConsumerMessages(eventName, idleTimeout = 30000) {
311
315
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
316
+ console.log(`PUBLISHER: Running recoverCrashedConsumerMessages`);
312
317
  const streamName = `${eventName}:${this.consumerGroupName}`;
313
318
  const pendingMessages = (yield this.redisGroups.xpending(streamName, this.consumerGroupName));
314
319
  if (!pendingMessages)
@@ -317,24 +322,24 @@ class Streams {
317
322
  if (!consumers || consumers.length === 0)
318
323
  return;
319
324
  for (const [consumer, pendingCount] of consumers) {
320
- const transaction = this.redisGroups.multi({ pipeline: true });
321
- if (parseInt(pendingCount) > 0) {
322
- const pending = (yield this.redisGroups.xpending(streamName, this.consumerGroupName, minId, maxId, Number(pendingCount), consumer));
323
- for (const [messageId] of pending) {
324
- const claimedMessage = (yield this.redisGroups.xclaim(streamName, this.consumerGroupName, this.instanceId, idleTimeout, messageId));
325
- if (claimedMessage) {
326
- console.log({ claimedMessage: JSON.stringify(claimedMessage) });
327
- const [, data] = claimedMessage[0];
328
- const eventData = JSON.parse(data[1]);
329
- const transaction = this.redisGroups.multi();
330
- transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
331
- transaction.publish(eventName, '');
332
- transaction.xack(streamName, this.consumerGroupName, messageId);
333
- yield transaction.exec().catch(publisherErrorHandler);
334
- }
325
+ if (parseInt(pendingCount) < 0)
326
+ return;
327
+ const pending = (yield this.redisGroups.xpending(streamName, this.consumerGroupName, minId, maxId, Number(pendingCount), consumer));
328
+ if (!pending)
329
+ return;
330
+ for (const [messageId] of pending) {
331
+ const claimedMessage = (yield this.redisGroups.xclaim(streamName, this.consumerGroupName, this.instanceId, idleTimeout, messageId));
332
+ if (claimedMessage) {
333
+ console.log({ claimedMessage: JSON.stringify(claimedMessage) });
334
+ const [, data] = claimedMessage[0];
335
+ const eventData = JSON.parse(data[1]);
336
+ const transaction = this.redisGroups.multi();
337
+ transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
338
+ transaction.publish(eventName, '');
339
+ transaction.xack(streamName, this.consumerGroupName, messageId);
340
+ yield transaction.exec().catch(publisherErrorHandler);
335
341
  }
336
342
  }
337
- yield transaction.exec();
338
343
  }
339
344
  });
340
345
  }
@@ -381,36 +386,51 @@ class Streams {
381
386
  let x = this.eventsListened.length;
382
387
  for (const eventName of this.eventsListened) {
383
388
  console.log(`${eventName} is being cleared in publisher`);
389
+ const streamName = `${eventName}:${this.consumerGroupName}`;
384
390
  yield this.redisGroups.srem(`${eventName}`, this.consumerGroupName);
385
391
  console.log(`${eventName} is removed from ${this.consumerGroupName}`);
386
392
  // Releasing all claims based on info from: https://redis.io/commands/xgroup-delconsumer/
387
- yield this.releaseAllClaims(eventName);
393
+ yield this.releaseAllClaims(streamName);
388
394
  console.log(`${eventName} removes all claims`);
389
- yield this.redisGroups.xgroup('DELCONSUMER', eventName, this.consumerGroupName, this.instanceId);
395
+ yield this.redisGroups.xgroup('DELCONSUMER', streamName, this.consumerGroupName, this.instanceId);
390
396
  console.log(`${eventName} is deleted as a consumer from ${this.consumerGroupName}, ${this.instanceId}`);
391
397
  console.log(x--);
392
398
  }
393
399
  });
394
400
  }
401
+ registerSubscribedEvent(eventName) {
402
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
403
+ const key = `instance:${this.instanceId}:subscribedEvents`;
404
+ console.log(`Registering event name for ${this.consumerGroupName} with key : ${key}`);
405
+ yield this.redisGroups.sadd(key, eventName);
406
+ });
407
+ }
395
408
  registerConsumerGroup(eventName) {
396
409
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
397
410
  yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
398
411
  });
399
412
  }
400
- releaseAllClaims(eventName) {
413
+ registerConsumerGroupName() {
414
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
415
+ const key = `instance:${this.instanceUniqueId}:consumerGroupName`;
416
+ console.log(`Registering service name ${this.consumerGroupName} for key : ${key}`);
417
+ yield this.redisGroups.set(key, this.consumerGroupName);
418
+ });
419
+ }
420
+ releaseAllClaims(streamName) {
401
421
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
402
422
  /**
403
423
  * Retrieve the pending messages for the consumer. Note this only fetches the last
404
424
  * 10000 events assigned to this consumer. This function has been modified to make sure
405
425
  * that there is a temp instance that claims all this messages
406
426
  */
407
- const pendingMessages = (yield this.redisGroups.xpending(eventName, this.consumerGroupName, '-', '+', 10000, this.instanceId));
427
+ const pendingMessages = (yield this.redisGroups.xpending(streamName, this.consumerGroupName, '-', '+', 10000, this.instanceId));
408
428
  if (pendingMessages && pendingMessages.length > 0) {
409
429
  console.log(`${pendingMessages.length} messages to clean up.`);
410
430
  const transaction = this.redisGroups.multi({ pipeline: true });
411
431
  const tempConsumerId = `${this.instanceId}-temp`;
412
432
  for (const [messageId] of pendingMessages) {
413
- transaction.xclaim(eventName, this.consumerGroupName, tempConsumerId, 10, messageId);
433
+ transaction.xclaim(streamName, this.consumerGroupName, tempConsumerId, 10, messageId);
414
434
  }
415
435
  yield transaction.exec();
416
436
  }