@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 +5 -5
- package/src/index.d.ts +1 -0
- package/src/lib/redis/groups.js +1 -1
- package/src/lib/redis/streams.d.ts +4 -4
- package/src/lib/redis/streams.js +17 -26
- package/src/lib/redis/types.d.ts +9 -3
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetit/publisher",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@jetit/id": "0.0.
|
|
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
package/src/lib/redis/groups.js
CHANGED
|
@@ -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(
|
|
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<
|
|
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:
|
|
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
|
package/src/lib/redis/streams.js
CHANGED
|
@@ -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 = (
|
|
45
|
+
this.cleanUpTimer = setInterval(() => {
|
|
46
46
|
this.clearDuplicationCheckKeys();
|
|
47
|
-
this.eventsListened.forEach((eventName) =>
|
|
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
|
|
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.
|
|
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
|
|
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(
|
|
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(
|
|
362
|
+
yield this.redisGroups.sadd(`${eventName}`, this.consumerGroupName);
|
|
372
363
|
});
|
|
373
364
|
}
|
|
374
365
|
cleanupAcknowledgedMessages(eventName, interval = 60 * 60 * 1000) {
|
package/src/lib/redis/types.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
export type EventData<
|
|
2
|
-
data:
|
|
3
|
-
eventName:
|
|
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]>;
|