@jetit/publisher 1.0.6 → 1.0.8

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.0.6",
3
+ "version": "1.0.8",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "@jetit/id": "0.0.6",
@@ -12,6 +12,5 @@
12
12
  "tslib": "2.5.0"
13
13
  },
14
14
  "main": "./src/index.js",
15
- "types": "./src/index.d.ts",
16
- "readme": "README.md"
15
+ "types": "./src/index.d.ts"
17
16
  }
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
@@ -44,7 +44,10 @@ class Streams {
44
44
  const cleanUpInterval = (_a = parseInt(process.env['CLEANUP_INTERVAL'] || '1000 * 60 * 60', 10)) !== null && _a !== void 0 ? _a : 1000 * 60 * 60;
45
45
  this.cleanUpTimer = (0, rxjs_1.interval)(cleanUpInterval).subscribe(() => {
46
46
  this.clearDuplicationCheckKeys();
47
- this.eventsListened.forEach((eventName) => this.cleanupAcknowledgedMessages(eventName, cleanUpInterval));
47
+ this.eventsListened.forEach((eventName) => {
48
+ this.cleanupAcknowledgedMessages(eventName, cleanUpInterval);
49
+ this.republishUnprocessedEvents(eventName);
50
+ });
48
51
  });
49
52
  }
50
53
  createConsumerGroup(eventName) {
@@ -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) {
@@ -362,13 +352,13 @@ class Streams {
362
352
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
363
353
  console.log(`${this.eventsListened.length} events to be cleared`);
364
354
  for (const eventName of this.eventsListened) {
365
- yield this.redisGroups.srem(`consumerGroups:${eventName}`, this.consumerGroupName);
355
+ yield this.redisGroups.srem(`${eventName}`, this.consumerGroupName);
366
356
  }
367
357
  });
368
358
  }
369
359
  registerConsumerGroup(eventName) {
370
360
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
371
- yield this.redisGroups.sadd(`consumerGroups:${eventName}`, this.consumerGroupName);
361
+ yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
372
362
  });
373
363
  }
374
364
  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]>;
package/src/README.md DELETED
@@ -1,43 +0,0 @@
1
- # publisher
2
-
3
- publisher is a library for implementing an event-driven architecture using Redis PUB/SUB and Redis Streams. It provides a simple and scalable mechanism for publishing and consuming events in real-time, and supports features such as message deduplication, consumer group management, and scheduled event publishing.
4
-
5
- ## Simple Example
6
-
7
- ```typescript
8
- import { Publisher, EventData } from '@jetit/streams';
9
-
10
- // Create an instance of the publisher
11
- const streams = new Streams('Websockets');
12
-
13
- // Publish an event
14
- const eventData: EventData<{ message: string }> = {
15
- eventName: 'my-event',
16
- data: { message: 'Hello, world!' }
17
- };
18
-
19
- await streams.publish(eventData);
20
-
21
- // Subscribe to an event
22
- streams.listen('my-event').subscribe(event => {
23
- console.log(`Received event: ${event.eventName}`, event.data);
24
- });
25
- ```
26
-
27
- ## Possible use cases
28
-
29
- 1. Microservices communication: If your system is composed of multiple microservices, the publisher can be used to facilitate communication between them by publishing and listening to events.
30
-
31
- 2. Event sourcing and CQRS: In an event-sourced system, the publisher can be used to store and process events that represent the state changes of the system, enabling Command Query Responsibility Segregation (CQRS) by separating the read and write models.
32
-
33
- 3. Task queues: The publisher can be used to create task queues for distributing workloads among different worker instances, ensuring that tasks are processed in the order they were created.
34
-
35
- 4. Data streaming and processing: The publisher can be used to ingest and process large volumes of data in real-time, such as log files, clickstream data, or other event-based data.
36
-
37
- 5. Distributed system coordination: In a distributed system, the publisher can be used for coordination between different components, such as managing leader election or maintaining configuration information.
38
-
39
- 6. Real-time analytics and monitoring: The publisher can be used to collect and process real-time analytics data, such as user behavior, application performance metrics, or system monitoring information.
40
-
41
- 7. Event-driven workflows: You can use the publisher to create event-driven workflows, where each step in the workflow is triggered by the completion of a previous step. This can be useful for orchestrating complex, multi-step processes.
42
-
43
- 8. Message broadcasting: The publisher can be used to broadcast messages to multiple consumers or subscribers, allowing for efficient and scalable communication in applications with many components or services.