@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
|
@@ -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;
|
package/src/lib/redis/streams.js
CHANGED
|
@@ -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 *
|
|
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));
|