@jetit/publisher 5.6.0 → 5.6.1

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": "5.6.0",
3
+ "version": "5.6.1",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "@jetit/id": "^0.0.13",
@@ -63,7 +63,7 @@ class ScheduledProcessor {
63
63
  .xadd(streamName, key, 'data', JSON.stringify(eventData))
64
64
  .catch((e) => logger_1.PUBLISHER_LOGGER.error(`PUBLISHER: Publishing event ${eventData.eventName} to consumer groups: ${consumerGroups.join(', ')} failed with data ${JSON.stringify(eventData)}, ${e} `));
65
65
  if (key === '*')
66
- key = generatedKey ?? key;
66
+ key = `${generatedKey ?? key}`;
67
67
  }
68
68
  if (eventData.repeatInterval) {
69
69
  const nextEventTime = currentTime + eventData.repeatInterval;
@@ -368,6 +368,17 @@ class Streams {
368
368
  * they need to be read using XRANGE.
369
369
  */
370
370
  if (multicast || processPending) {
371
+ /**
372
+ * Very very rare case of this occurring. Cases where the running service is super overloaded
373
+ * that causes a messaged to be sent to processing with a delay, but eventually before being
374
+ * processed gets picked up by another instance, leading to multiple publications
375
+ */
376
+ if (processPending) {
377
+ const claimed = await redisClient.xclaim(streamName, this.consumerGroupName, this.instanceId, 20000, messageId, 'JUSTID');
378
+ if (!claimed || claimed.length === 0) {
379
+ return; // Message already claimed or acknowledged by another consumer, so don't repush to the subscriber
380
+ }
381
+ }
371
382
  const messages = await redisClient.xrange(streamName, messageId, messageId);
372
383
  if (messages?.length) {
373
384
  try {
@@ -469,13 +480,31 @@ class Streams {
469
480
  /** Process Unprocessed Messages with rate limiting */
470
481
  if (!processPending) {
471
482
  const unprocessedMessageIds = await (0, utils_1.getUnacknowledgedMessages)(redisClient, this.consumerGroupName, streamName, this.instanceId);
483
+ /**
484
+ * Dealing with the case where messages don't get processed due to large
485
+ * batch sizes. The previous default was 20ms, which seemed to work in
486
+ * most cases but seem to fail when the number of retry messages are high.
487
+ *
488
+ * The old solution did not take into account the fact that this library
489
+ * is dependent on the infrastructure of the app that runs it, so any memory/
490
+ * resource/stack overload on the app has an impact in this
491
+ */
492
+ const getDelay = (count) => {
493
+ if (count > 100)
494
+ return 500; // 500ms for large backlogs
495
+ if (count > 50)
496
+ return 300; // 300ms for medium-large
497
+ if (count > 20)
498
+ return 200; // 200ms for medium
499
+ return 100; // 100ms for small
500
+ };
472
501
  if (unprocessedMessageIds.countOnThisConsumer &&
473
502
  unprocessedMessageIds.countOnThisConsumer > this.config.unprocessedMessageThreshold) {
474
503
  logger_1.PUBLISHER_LOGGER.error(`PUBLISHER: Too many unprocessed events for ${streamName}: count: ${unprocessedMessageIds.count}`);
475
504
  }
476
505
  // Process messages with rate limiting
477
506
  const processWithDelay = async (id, index) => {
478
- await new Promise((resolve) => setTimeout(resolve, index * 20));
507
+ await new Promise((resolve) => setTimeout(resolve, index * getDelay(unprocessedMessageIds.countOnThisConsumer ?? 1)));
479
508
  await processMessage(redisClient, id, new tracker_1.MetricsTracker(), multicast, true);
480
509
  };
481
510
  unprocessedMessageIds.messageIds.map((id, index) => processWithDelay(id, index));