@jetit/publisher 6.0.1 → 6.0.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/README.md CHANGED
@@ -126,6 +126,7 @@ const config: Partial<IStreamsConfig> = {
126
126
  maxStoredEvents: 5000,
127
127
  },
128
128
  maxPendingTasks: 1000, // Max concurrent pending retry tasks per event per consumer (default: 1000, 0 = unbounded)
129
+ enableMetrics: true, // Set to false to disable MetricsCollector and its periodic SCAN (default: true)
129
130
  };
130
131
 
131
132
  const publisher = new Publisher('MyService', config);
@@ -359,6 +360,7 @@ The Circuit Breaker has three states:
359
360
  - Retry logic with exponential backoff for failed operations
360
361
  - Circuit Breaker to prevent overwhelming failed services
361
362
  - Dead Letter Queue (DLQ) for handling subscription failures
363
+ - **Disable Metrics Collection**: Set `enableMetrics: false` to skip `MetricsCollector` initialization entirely. The collector runs `SCAN *:cg-* COUNT 100` every 60 seconds for queue depth — disabling it eliminates this periodic Redis overhead. Applies to both `Publisher` and `PublisherLite`. When disabled, `getMetrics()` returns `[]` and `getLatestMetrics()` returns `null`.
362
364
  - **Pending Retry Task Cap**: Limits the number of concurrent in-flight pending message retry tasks per event per consumer instance. Prevents unbounded memory growth and Redis saturation under sustained load. Configurable via `maxPendingTasks` (default: 1000). Set to `0` to disable the cap (unbounded, pre-6.0.1 behavior). When the cap is reached, a rate-limited warning is logged and skipped messages are retried on the next Pub/Sub trigger.
363
365
  - **Adaptive Redis Stream ID Generation (Publisher only)**: The default `Publisher` automatically switches to an optimized ID generation strategy using a Lua script when publishing to many consumer groups (>10 by default) or when ID conflicts are detected. This prevents `XADD` errors related to non-monotonic IDs in high-throughput scenarios. Configurable via `optimizationThreshold` and `optimizationDurationMs`. (`PublisherLite` does not include this complex logic).
364
366
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetit/publisher",
3
- "version": "6.0.1",
3
+ "version": "6.0.2",
4
4
  "type": "commonjs",
5
5
  "peerDependencies": {
6
6
  "@jetit/id": ">=0.0.14",
@@ -8,7 +8,7 @@ export declare class StreamsLite {
8
8
  private _redisGroups?;
9
9
  private config;
10
10
  private dlq;
11
- private metricsCollector;
11
+ private metricsCollector?;
12
12
  private consumerGroupName;
13
13
  private instanceId;
14
14
  private instanceUniqueId;
@@ -75,11 +75,13 @@ class StreamsLite {
75
75
  }, cleanUpInterval);
76
76
  logger_1.PUBLISHER_LOGGER.log(`PUBLISHER: Clean Up process setup for ${cleanUpInterval} ms`);
77
77
  this.dlq = new dlq_1.DeadLetterQueue(this.redisPublisher, config.dlqEventThreshold);
78
- this.metricsCollector = new collector_1.MetricsCollector({
79
- redisClient: this.redisPublisher,
80
- collectionInterval: 60000,
81
- retentionPeriod: 6 * 60 * 60 * 1000,
82
- }, this.dlq);
78
+ if (this.config.enableMetrics !== false) {
79
+ this.metricsCollector = new collector_1.MetricsCollector({
80
+ redisClient: this.redisPublisher,
81
+ collectionInterval: 60000,
82
+ retentionPeriod: 6 * 60 * 60 * 1000,
83
+ }, this.dlq);
84
+ }
83
85
  this.duplicateChecker = new duplication_1.ContentBasedDeduplication(this.redisPublisher, this.config.duplicationCheckWindow);
84
86
  this.circuitBreaker = new circuit_breaker_1.CircuitBreaker(this.config.circuitBreaker, this.redisPublisher);
85
87
  if (this.config.circuitBreaker.enabled)
@@ -667,6 +669,8 @@ class StreamsLite {
667
669
  * This will return you the stats of the publisher for the last 6 hours after cleaning
668
670
  */
669
671
  async getMetrics(startTime, endTime) {
672
+ if (!this.metricsCollector)
673
+ return [];
670
674
  return this.metricsCollector.getMetrics(startTime, endTime);
671
675
  }
672
676
  /**
@@ -674,6 +678,8 @@ class StreamsLite {
674
678
  * This will return you the latest stats of the publisher
675
679
  */
676
680
  async getLatestMetrics() {
681
+ if (!this.metricsCollector)
682
+ return null;
677
683
  return this.metricsCollector.getLatestMetrics();
678
684
  }
679
685
  /**
@@ -8,7 +8,7 @@ export declare class Streams {
8
8
  private _redisGroups?;
9
9
  private config;
10
10
  private dlq;
11
- private metricsCollector;
11
+ private metricsCollector?;
12
12
  private consumerGroupName;
13
13
  private instanceId;
14
14
  private instanceUniqueId;
@@ -129,6 +129,7 @@ class Streams {
129
129
  optimizationDurationMs: 2 * 60 * 1000, // 2 minutes
130
130
  optimizationThreshold: 20, // Enable optimization for >20 consumer groups
131
131
  maxPendingTasks: 1000,
132
+ enableMetrics: true,
132
133
  };
133
134
  /** Initialise Config properties */
134
135
  this.config = { ...this.config, ...this.DEFAULT_STREAMS_CONFIG, ...config };
@@ -144,11 +145,13 @@ class Streams {
144
145
  }, cleanUpInterval);
145
146
  logger_1.PUBLISHER_LOGGER.log(`PUBLISHER: Clean Up process setup for ${cleanUpInterval} ms`);
146
147
  this.dlq = new dlq_1.DeadLetterQueue(this.redisPublisher, config.dlqEventThreshold);
147
- this.metricsCollector = new collector_1.MetricsCollector({
148
- redisClient: this.redisPublisher,
149
- collectionInterval: 60000,
150
- retentionPeriod: 6 * 60 * 60 * 1000,
151
- }, this.dlq);
148
+ if (this.config.enableMetrics !== false) {
149
+ this.metricsCollector = new collector_1.MetricsCollector({
150
+ redisClient: this.redisPublisher,
151
+ collectionInterval: 60000,
152
+ retentionPeriod: 6 * 60 * 60 * 1000,
153
+ }, this.dlq);
154
+ }
152
155
  this.duplicateChecker = new duplication_1.ContentBasedDeduplication(this.redisPublisher, this.config.duplicationCheckWindow);
153
156
  this.circuitBreaker = new circuit_breaker_1.CircuitBreaker(this.config.circuitBreaker, this.redisPublisher);
154
157
  if (this.config.circuitBreaker.enabled)
@@ -1032,6 +1035,8 @@ class Streams {
1032
1035
  * This will return you the stats of the publisher for the last 6 hours after cleaning
1033
1036
  */
1034
1037
  async getMetrics(startTime, endTime) {
1038
+ if (!this.metricsCollector)
1039
+ return [];
1035
1040
  return this.metricsCollector.getMetrics(startTime, endTime);
1036
1041
  }
1037
1042
  /**
@@ -1039,6 +1044,8 @@ class Streams {
1039
1044
  * This will return you the latest stats of the publisher
1040
1045
  */
1041
1046
  async getLatestMetrics() {
1047
+ if (!this.metricsCollector)
1048
+ return null;
1042
1049
  return this.metricsCollector.getLatestMetrics();
1043
1050
  }
1044
1051
  /**
@@ -57,6 +57,7 @@ export interface IStreamsConfig {
57
57
  optimizationDurationMs?: number;
58
58
  optimizationThreshold?: number;
59
59
  maxPendingTasks?: number;
60
+ enableMetrics?: boolean;
60
61
  }
61
62
  export type TEventFilter<T> = (event: EventData<T, string>) => boolean;
62
63
  export interface ISubscription<T, TName extends string = string> {