@jetit/publisher 1.0.7 → 1.0.9

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,15 +1,15 @@
1
1
  {
2
2
  "name": "@jetit/publisher",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
- "@jetit/id": "0.0.6",
6
+ "@jetit/id": "0.0.11",
7
7
  "ioredis": "5.3.1",
8
- "rxjs": "7.8.0"
8
+ "rxjs": "7.8.0",
9
+ "tslib": "2.5.0"
9
10
  },
10
11
  "peerDependencies": {
11
- "@types/ioredis-mock": "8.2.1",
12
- "tslib": "2.5.0"
12
+ "@types/ioredis-mock": "8.2.1"
13
13
  },
14
14
  "main": "./src/index.js",
15
15
  "types": "./src/index.d.ts"
package/src/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './lib/publisher';
2
+ export { EventData } from './lib/redis/types';
@@ -4,7 +4,7 @@ exports.getAllConsumerGroups = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  function getAllConsumerGroups(eventName, redisConnection) {
6
6
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
7
- const consumerGroups = yield redisConnection.smembers(`consumerGroups:${eventName}`);
7
+ const consumerGroups = yield redisConnection.smembers(`${eventName}`);
8
8
  return consumerGroups;
9
9
  });
10
10
  }
@@ -1,5 +1,5 @@
1
1
  import { RedisType } from './registry';
2
- import { EventData } from './types';
2
+ import { EventData, PublishData } from './types';
3
3
  import { Observable } from 'rxjs';
4
4
  export declare class Streams {
5
5
  private _redisPublisher?;
@@ -47,7 +47,7 @@ export declare class Streams {
47
47
  * const eventData = { eventName: 'order.created', data: orderData };
48
48
  * await streams.publish(eventData);
49
49
  */
50
- publish<T>(data: EventData<T>): Promise<void>;
50
+ publish<TData = unknown, TName extends string = string>(data: PublishData<TData, TName>): Promise<void>;
51
51
  /**
52
52
  * Schedules an event to be published at a specified future time. Thee event gets published if the
53
53
  * differnece between the current time and the scheduled time is less than 500ms.
@@ -69,7 +69,7 @@ export declare class Streams {
69
69
  *
70
70
  * await streams.scheduledPublish(futureTime, eventData);
71
71
  */
72
- scheduledPublish<T>(scheduledTime: Date, eventData: EventData<T>, uniquePerInstance?: boolean): Promise<void>;
72
+ scheduledPublish<T, const TName extends string = string>(scheduledTime: Date, eventData: EventData<T, TName>, uniquePerInstance?: boolean): Promise<void>;
73
73
  /**
74
74
  * Listens for events with the given name and returns an Observable that emits an EventData<T> object
75
75
  * each time a new event is received.
@@ -97,7 +97,7 @@ export declare class Streams {
97
97
  * console.log('New order created:', event.data);
98
98
  * });
99
99
  */
100
- listen<T>(eventName: string, maxRetries?: number, initialDelay?: number): Observable<EventData<T>>;
100
+ listen<T = unknown, const TName extends string = string>(eventName: TName, maxRetries?: number, initialDelay?: number): Observable<EventData<T, TName>>;
101
101
  private listenInternals;
102
102
  /**
103
103
  * This method takes all messages allocated to this instance and republishes them so
@@ -42,10 +42,13 @@ class Streams {
42
42
  this.instanceId = `${serviceName}:${(0, id_1.generateID)('HEX', 'FE')}`;
43
43
  this.consumerGroupName = `cg-${serviceName}`;
44
44
  const cleanUpInterval = (_a = parseInt(process.env['CLEANUP_INTERVAL'] || '1000 * 60 * 60', 10)) !== null && _a !== void 0 ? _a : 1000 * 60 * 60;
45
- this.cleanUpTimer = (0, rxjs_1.interval)(cleanUpInterval).subscribe(() => {
45
+ this.cleanUpTimer = setInterval(() => {
46
46
  this.clearDuplicationCheckKeys();
47
- this.eventsListened.forEach((eventName) => this.cleanupAcknowledgedMessages(eventName, cleanUpInterval));
48
- });
47
+ this.eventsListened.forEach((eventName) => {
48
+ this.cleanupAcknowledgedMessages(eventName, cleanUpInterval);
49
+ this.republishUnprocessedEvents(eventName);
50
+ });
51
+ }, cleanUpInterval);
49
52
  }
50
53
  createConsumerGroup(eventName) {
51
54
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
@@ -85,28 +88,15 @@ class Streams {
85
88
  } while (cursor !== '0');
86
89
  });
87
90
  }
88
- /**
89
- * Publishes an event with the given data to the Redis event stream.
90
- *
91
- * The method generates a unique event ID for each event, and adds it to the event data to handle message
92
- * deduplication.
93
- *
94
- * @param data - An EventData<T> object containing the data for the event.
95
- *
96
- * @returns A Promise that resolves when the event has been published to the Redis stream.
97
- *
98
- * @example
99
- *
100
- * // Publish an "order.created" event with the given order data
101
- * const orderData = { id: '123', customerName: 'John Doe', amount: 100 };
102
- * const eventData = { eventName: 'order.created', data: orderData };
103
- * await streams.publish(eventData);
104
- */
105
91
  publish(data) {
106
92
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
107
- data.eventId = (0, id_1.generateID)('HEX', 'FF'); // Added a unique Id to handle Message deduplication
93
+ if (data.eventId)
94
+ data.republishEvent = data.eventId;
95
+ data.eventId = (0, id_1.generateID)('HEX', 'FF');
96
+ if (!data.createdAt)
97
+ data.createdAt = Date.now();
108
98
  const transaction = this.redisPublisher.multi();
109
- const consumerGroups = yield (0, groups_1.getAllConsumerGroups)(data.eventName, this.redisGroups);
99
+ const consumerGroups = yield (0, groups_1.getAllConsumerGroups)(data.eventName, this.redisPublisher);
110
100
  if (consumerGroups.length > 0) {
111
101
  console.log(`Publishing event ${data.eventName} to consumer groups: ${consumerGroups.join(', ')}`);
112
102
  for (const consumerGroup of consumerGroups) {
@@ -268,15 +258,16 @@ class Streams {
268
258
  const result = yield this.redisGroups.xreadgroup('GROUP', this.consumerGroupName, this.instanceId, 'STREAMS', streamName, '>');
269
259
  if (result) {
270
260
  const [, streamMessages] = result[0];
261
+ console.log(`Unprocessed events: ${streamMessages.length}`);
271
262
  for (const [id, data] of streamMessages) {
272
263
  const eventData = JSON.parse(data[1]);
273
- console.log(`Unprocessed event: ${id}, data:`, eventData);
274
264
  const transaction = this.redisGroups.multi();
275
265
  // Republishing the events
276
266
  transaction.xadd(streamName, '*', 'data', JSON.stringify(eventData));
277
267
  transaction.publish(eventName, '');
278
268
  transaction.xack(streamName, this.consumerGroupName, id);
279
269
  yield transaction.exec();
270
+ console.log(`Event ${eventName} with ID: ${id} published`);
280
271
  }
281
272
  }
282
273
  });
@@ -354,7 +345,7 @@ class Streams {
354
345
  yield this.redisGroups.quit();
355
346
  }
356
347
  if (this.cleanUpTimer) {
357
- this.cleanUpTimer.unsubscribe();
348
+ clearInterval(this.cleanUpTimer);
358
349
  }
359
350
  });
360
351
  }
@@ -362,13 +353,13 @@ class Streams {
362
353
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
363
354
  console.log(`${this.eventsListened.length} events to be cleared`);
364
355
  for (const eventName of this.eventsListened) {
365
- yield this.redisGroups.srem(`consumerGroups:${eventName}`, this.consumerGroupName);
356
+ yield this.redisGroups.srem(`${eventName}`, this.consumerGroupName);
366
357
  }
367
358
  });
368
359
  }
369
360
  registerConsumerGroup(eventName) {
370
361
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
371
- yield this.redisGroups.sadd(`consumerGroups:${eventName}`, this.consumerGroupName);
362
+ yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
372
363
  });
373
364
  }
374
365
  cleanupAcknowledgedMessages(eventName, interval = 60 * 60 * 1000) {
@@ -1,7 +1,13 @@
1
- export type EventData<T> = {
2
- data: T;
3
- eventName: string;
1
+ export type EventData<TData, TName extends string> = {
2
+ data: TData;
3
+ eventName: TName;
4
4
  eventId?: string;
5
+ createdAt?: number;
6
+ republishEvent?: string;
7
+ };
8
+ export type PublishData<TData, TName extends string> = {
9
+ data: TData;
10
+ eventName: TName;
5
11
  };
6
12
  export type PendingMessages = [never, never, string, string, Array<[string, number]>];
7
13
  export type ClaimedMessages = Array<[never, string]>;