@jetit/publisher 4.1.1 → 5.1.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/README.md +249 -171
- package/package.json +3 -2
- package/src/lib/monitoring/adapters/prom.d.ts +42 -0
- package/src/lib/monitoring/adapters/prom.js +179 -0
- package/src/lib/monitoring/collector.d.ts +22 -0
- package/src/lib/monitoring/collector.js +163 -0
- package/src/lib/monitoring/tracker.d.ts +20 -0
- package/src/lib/monitoring/tracker.js +106 -0
- package/src/lib/monitoring/types.d.ts +58 -0
- package/src/lib/monitoring/types.js +2 -0
- package/src/lib/performance/circuit_breaker.d.ts +29 -0
- package/src/lib/performance/circuit_breaker.js +103 -0
- package/src/lib/publisher.d.ts +3 -0
- package/src/lib/publisher.js +6 -1
- package/src/lib/redis/batch.d.ts +6 -0
- package/src/lib/redis/batch.js +79 -0
- package/src/lib/redis/dlq.d.ts +18 -0
- package/src/lib/redis/dlq.js +133 -0
- package/src/lib/redis/duplication.d.ts +10 -0
- package/src/lib/redis/duplication.js +30 -0
- package/src/lib/redis/scheduler.js +1 -1
- package/src/lib/redis/streams.d.ts +61 -3
- package/src/lib/redis/streams.js +407 -77
- package/src/lib/redis/types.d.ts +64 -0
package/src/lib/publisher.d.ts
CHANGED
|
@@ -2,3 +2,6 @@ export { setRedisConnectionSettings as setRedisConfig } from './redis/registry';
|
|
|
2
2
|
export { Streams as Publisher } from './redis/streams';
|
|
3
3
|
export { ScheduledProcessor as __SCHEDULER_INTERNALS__ } from './redis/scheduler';
|
|
4
4
|
export { UTILS as StreamUtilityFunctions } from './redis/utils';
|
|
5
|
+
export { PrometheusAdapter } from './monitoring/adapters/prom';
|
|
6
|
+
export { publishBatch, publishScheduledBatch } from './redis/batch';
|
|
7
|
+
export { IListenOptions, IStreamsConfig, TEventFilter } from './redis/types';
|
package/src/lib/publisher.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StreamUtilityFunctions = exports.__SCHEDULER_INTERNALS__ = exports.Publisher = exports.setRedisConfig = void 0;
|
|
3
|
+
exports.publishScheduledBatch = exports.publishBatch = exports.PrometheusAdapter = exports.StreamUtilityFunctions = exports.__SCHEDULER_INTERNALS__ = exports.Publisher = exports.setRedisConfig = void 0;
|
|
4
4
|
var registry_1 = require("./redis/registry");
|
|
5
5
|
Object.defineProperty(exports, "setRedisConfig", { enumerable: true, get: function () { return registry_1.setRedisConnectionSettings; } });
|
|
6
6
|
var streams_1 = require("./redis/streams");
|
|
@@ -9,3 +9,8 @@ var scheduler_1 = require("./redis/scheduler");
|
|
|
9
9
|
Object.defineProperty(exports, "__SCHEDULER_INTERNALS__", { enumerable: true, get: function () { return scheduler_1.ScheduledProcessor; } });
|
|
10
10
|
var utils_1 = require("./redis/utils");
|
|
11
11
|
Object.defineProperty(exports, "StreamUtilityFunctions", { enumerable: true, get: function () { return utils_1.UTILS; } });
|
|
12
|
+
var prom_1 = require("./monitoring/adapters/prom");
|
|
13
|
+
Object.defineProperty(exports, "PrometheusAdapter", { enumerable: true, get: function () { return prom_1.PrometheusAdapter; } });
|
|
14
|
+
var batch_1 = require("./redis/batch");
|
|
15
|
+
Object.defineProperty(exports, "publishBatch", { enumerable: true, get: function () { return batch_1.publishBatch; } });
|
|
16
|
+
Object.defineProperty(exports, "publishScheduledBatch", { enumerable: true, get: function () { return batch_1.publishScheduledBatch; } });
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Streams as Publisher } from './streams';
|
|
2
|
+
import { BatchPublishOptions, BatchPublishResult, PublishData } from './types';
|
|
3
|
+
export declare function publishBatch<TData, TName extends string>(streams: Publisher, events: Array<PublishData<TData, TName>>, options?: BatchPublishOptions): Promise<BatchPublishResult<TData, TName>>;
|
|
4
|
+
export declare function publishScheduledBatch<TData, TName extends string>(streams: Publisher, events: Array<PublishData<TData, TName>>, options: BatchPublishOptions & {
|
|
5
|
+
scheduledTime: Date;
|
|
6
|
+
}): Promise<BatchPublishResult<TData, TName>>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.publishScheduledBatch = exports.publishBatch = void 0;
|
|
4
|
+
const id_1 = require("@jetit/id");
|
|
5
|
+
const tracker_1 = require("../monitoring/tracker");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
async function delay(ms) {
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
|
+
}
|
|
10
|
+
async function publishSingleEvent(streams, event, batchId, tracker, scheduledTime) {
|
|
11
|
+
try {
|
|
12
|
+
tracker.startRedisOperation();
|
|
13
|
+
let eventId = '';
|
|
14
|
+
if (scheduledTime) {
|
|
15
|
+
await streams.scheduledPublish(scheduledTime, { ...event, batchId });
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
eventId = await streams.publish({ ...event, batchId });
|
|
19
|
+
}
|
|
20
|
+
tracker.endRedisOperation();
|
|
21
|
+
return { eventName: event.eventName, eventId, success: true };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return { eventName: event.eventName, eventId: '', success: false, error: error.message };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function publishBatchWithRetry(streams, events, options) {
|
|
28
|
+
const batchId = (0, id_1.generateID)('HEX');
|
|
29
|
+
const tracker = new tracker_1.MetricsTracker();
|
|
30
|
+
let results = [];
|
|
31
|
+
const batchSize = options.batchSize || 100;
|
|
32
|
+
const delayBetweenBatches = options.delayBetweenBatches || 1000;
|
|
33
|
+
/** First attempt: publish all events in chunks */
|
|
34
|
+
for (let i = 0; i < events.length; i += batchSize) {
|
|
35
|
+
const chunk = events.slice(i, i + batchSize);
|
|
36
|
+
tracker.startProcessing();
|
|
37
|
+
const chunkResults = await Promise.all(chunk.map((event) => publishSingleEvent(streams, event, batchId, tracker, options.scheduledTime)));
|
|
38
|
+
tracker.endProcessing();
|
|
39
|
+
results.push(...chunkResults);
|
|
40
|
+
if (i + batchSize < events.length) {
|
|
41
|
+
await delay(delayBetweenBatches);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Second attempt: retry failed events once */
|
|
45
|
+
const failedEvents = results.filter((result) => !result.success);
|
|
46
|
+
if (failedEvents.length > 0) {
|
|
47
|
+
logger_1.PERFORMANCE_LOGGER.log(`${options.scheduledTime ? 'SCHEDULED_' : ''}BATCH_RETRY;${batchId};${failedEvents.length}`);
|
|
48
|
+
const retryResults = await Promise.all(failedEvents.map((result) => {
|
|
49
|
+
const event = events.find((event) => event.eventName === result.eventName);
|
|
50
|
+
return publishSingleEvent(streams, event, batchId, tracker, options.scheduledTime);
|
|
51
|
+
}));
|
|
52
|
+
results = results.map((result) => {
|
|
53
|
+
if (!result.success) {
|
|
54
|
+
const retryResult = retryResults.find((retry) => retry.eventName === result.eventName);
|
|
55
|
+
return retryResult || result;
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const metrics = tracker.getMetrics();
|
|
61
|
+
const averageEventTime = metrics.totalTime / events.length;
|
|
62
|
+
logger_1.PERFORMANCE_LOGGER.log(`${options.scheduledTime ? 'SCHEDULED_' : ''}BATCH;${batchId};${events.length};${metrics.totalTime};${metrics.redisOperationTime};${metrics.processingTime};${averageEventTime}${options.scheduledTime ? `;${options.scheduledTime.getTime()}` : ''}`);
|
|
63
|
+
return {
|
|
64
|
+
batchId,
|
|
65
|
+
results,
|
|
66
|
+
performanceMetrics: {
|
|
67
|
+
...metrics,
|
|
68
|
+
averageEventTime,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function publishBatch(streams, events, options = {}) {
|
|
73
|
+
return publishBatchWithRetry(streams, events, options);
|
|
74
|
+
}
|
|
75
|
+
exports.publishBatch = publishBatch;
|
|
76
|
+
function publishScheduledBatch(streams, events, options) {
|
|
77
|
+
return publishBatchWithRetry(streams, events, options);
|
|
78
|
+
}
|
|
79
|
+
exports.publishScheduledBatch = publishScheduledBatch;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RedisType } from './registry';
|
|
2
|
+
import { IDLQEvent } from './types';
|
|
3
|
+
export declare class DeadLetterQueue {
|
|
4
|
+
private redisClient;
|
|
5
|
+
private maxEventsThreshold;
|
|
6
|
+
constructor(redisClient: RedisType, maxEventsThreshold?: number);
|
|
7
|
+
addToDLQ(event: IDLQEvent): Promise<void>;
|
|
8
|
+
getFromDLQ(start?: number, end?: number): Promise<IDLQEvent[]>;
|
|
9
|
+
retryFromDLQ(eventId: string): Promise<boolean>;
|
|
10
|
+
removeFromDLQ(eventId: string): Promise<boolean>;
|
|
11
|
+
cleanupDLQ(): Promise<void>;
|
|
12
|
+
getDLQStats(): Promise<{
|
|
13
|
+
size: number;
|
|
14
|
+
additionRate: number;
|
|
15
|
+
}>;
|
|
16
|
+
private isRateLimitExceeded;
|
|
17
|
+
private incrementRateLimit;
|
|
18
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeadLetterQueue = void 0;
|
|
4
|
+
const logger_1 = require("./logger");
|
|
5
|
+
const DLQ_HASH_KEY = 'dlq_events';
|
|
6
|
+
const DLQ_ZSET_KEY = 'dlq_order';
|
|
7
|
+
const DLQ_RATE_LIMIT_KEY = 'dlq_rate_limit';
|
|
8
|
+
const DLQ_EXPIRATION = 24 * 60 * 60 * 1000; // 24 hours
|
|
9
|
+
class DeadLetterQueue {
|
|
10
|
+
constructor(redisClient, maxEventsThreshold = 1000) {
|
|
11
|
+
this.redisClient = redisClient;
|
|
12
|
+
this.maxEventsThreshold = maxEventsThreshold;
|
|
13
|
+
}
|
|
14
|
+
async addToDLQ(event) {
|
|
15
|
+
try {
|
|
16
|
+
if (await this.isRateLimitExceeded()) {
|
|
17
|
+
logger_1.PUBLISHER_LOGGER.warn('DLQ: Rate limit exceeded, not adding event to DLQ');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const eventJson = JSON.stringify(event);
|
|
21
|
+
await this.redisClient.multi().hset(DLQ_HASH_KEY, event.eventId, eventJson).zadd(DLQ_ZSET_KEY, event.timestamp, event.eventId).exec();
|
|
22
|
+
await this.incrementRateLimit();
|
|
23
|
+
logger_1.PUBLISHER_LOGGER.log(`DLQ: Added event ${event.eventId} to Dead Letter Queue`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
logger_1.PUBLISHER_LOGGER.error('DLQ: Error adding event to Dead Letter Queue', error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async getFromDLQ(start = 0, end = -1) {
|
|
30
|
+
try {
|
|
31
|
+
const eventIds = await this.redisClient.zrange(DLQ_ZSET_KEY, start, end);
|
|
32
|
+
const events = await this.redisClient.hmget(DLQ_HASH_KEY, ...eventIds);
|
|
33
|
+
return events
|
|
34
|
+
.filter((x) => !!x)
|
|
35
|
+
.map((event) => JSON.parse(event ?? ''))
|
|
36
|
+
.filter((event) => event !== null);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger_1.PUBLISHER_LOGGER.error('DLQ: Error retrieving events from Dead Letter Queue', error);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async retryFromDLQ(eventId) {
|
|
44
|
+
try {
|
|
45
|
+
const eventJson = await this.redisClient.hget(DLQ_HASH_KEY, eventId);
|
|
46
|
+
if (!eventJson) {
|
|
47
|
+
logger_1.PUBLISHER_LOGGER.warn(`DLQ: Event with ID ${eventId} not found in Dead Letter Queue`);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const event = JSON.parse(eventJson);
|
|
51
|
+
// Attempt to republish the event to its original stream
|
|
52
|
+
const streamName = event.originalStream;
|
|
53
|
+
const result = await this.redisClient.xadd(streamName, '*', 'data', JSON.stringify(event));
|
|
54
|
+
if (result) {
|
|
55
|
+
// If successful, remove the event from the DLQ
|
|
56
|
+
await this.removeFromDLQ(eventId);
|
|
57
|
+
logger_1.PUBLISHER_LOGGER.log(`DLQ: Successfully retried and removed event ${eventId} from Dead Letter Queue`);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
logger_1.PUBLISHER_LOGGER.error(`DLQ: Failed to republish event ${eventId} to stream ${streamName}`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
logger_1.PUBLISHER_LOGGER.error(`DLQ: Error retrying event ${eventId} from Dead Letter Queue`, error);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async removeFromDLQ(eventId) {
|
|
71
|
+
try {
|
|
72
|
+
const removed = await this.redisClient.multi().hdel(DLQ_HASH_KEY, eventId).zrem(DLQ_ZSET_KEY, eventId).exec();
|
|
73
|
+
if (removed && removed[0][1] === 1 && removed[1][1] === 1) {
|
|
74
|
+
logger_1.PUBLISHER_LOGGER.log(`DLQ: Successfully removed event ${eventId} from Dead Letter Queue`);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
logger_1.PUBLISHER_LOGGER.warn(`DLQ: Event with ID ${eventId} not found in Dead Letter Queue for removal`);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
logger_1.PUBLISHER_LOGGER.error(`DLQ: Error removing event ${eventId} from Dead Letter Queue`, error);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async cleanupDLQ() {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const cutoffTime = now - DLQ_EXPIRATION;
|
|
90
|
+
try {
|
|
91
|
+
const expiredEventIds = await this.redisClient.zrangebyscore(DLQ_ZSET_KEY, 0, cutoffTime);
|
|
92
|
+
if (expiredEventIds.length > 0) {
|
|
93
|
+
await this.redisClient
|
|
94
|
+
.multi()
|
|
95
|
+
.hdel(DLQ_HASH_KEY, ...expiredEventIds)
|
|
96
|
+
.zremrangebyscore(DLQ_ZSET_KEY, 0, cutoffTime)
|
|
97
|
+
.exec();
|
|
98
|
+
}
|
|
99
|
+
logger_1.PUBLISHER_LOGGER.log(`DLQ: Cleaned up ${expiredEventIds.length} expired events from Dead Letter Queue`);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger_1.PUBLISHER_LOGGER.error('DLQ: Error cleaning up Dead Letter Queue', error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async getDLQStats() {
|
|
106
|
+
try {
|
|
107
|
+
const results = await this.redisClient.multi().zcard(DLQ_ZSET_KEY).get(DLQ_RATE_LIMIT_KEY).exec();
|
|
108
|
+
if (!results) {
|
|
109
|
+
throw new Error('Failed to execute Redis commands');
|
|
110
|
+
}
|
|
111
|
+
const [sizeResult, additionRateResult] = results;
|
|
112
|
+
if (sizeResult[0] || additionRateResult[0]) {
|
|
113
|
+
throw new Error('Error executing Redis commands');
|
|
114
|
+
}
|
|
115
|
+
const size = sizeResult[1];
|
|
116
|
+
const additionRate = parseInt(additionRateResult[1] || '0', 10);
|
|
117
|
+
return { size, additionRate };
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
logger_1.PUBLISHER_LOGGER.error('DLQ: Error getting Dead Letter Queue stats', error);
|
|
121
|
+
return { size: 0, additionRate: 0 };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async isRateLimitExceeded() {
|
|
125
|
+
const currentRate = (await this.redisClient.get(DLQ_RATE_LIMIT_KEY)) || '0';
|
|
126
|
+
return parseInt(currentRate, 10) >= this.maxEventsThreshold;
|
|
127
|
+
}
|
|
128
|
+
async incrementRateLimit() {
|
|
129
|
+
await this.redisClient.incr(DLQ_RATE_LIMIT_KEY);
|
|
130
|
+
await this.redisClient.expire(DLQ_RATE_LIMIT_KEY, 60); // Reset rate limit after 1 minute
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.DeadLetterQueue = DeadLetterQueue;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RedisType } from './registry';
|
|
2
|
+
import { EventData } from './types';
|
|
3
|
+
export declare class ContentBasedDeduplication {
|
|
4
|
+
private redisClient;
|
|
5
|
+
private ttl;
|
|
6
|
+
private hmacSecret;
|
|
7
|
+
constructor(redisClient: RedisType, ttl?: number);
|
|
8
|
+
private calculateEventHash;
|
|
9
|
+
isDuplicate(event: EventData<any, string>, consumerGroupName: string): Promise<boolean>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentBasedDeduplication = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const logger_1 = require("./logger");
|
|
6
|
+
class ContentBasedDeduplication {
|
|
7
|
+
constructor(redisClient, ttl = 86400) {
|
|
8
|
+
this.redisClient = redisClient;
|
|
9
|
+
this.ttl = ttl;
|
|
10
|
+
this.hmacSecret = 'content-hash-calculation';
|
|
11
|
+
}
|
|
12
|
+
calculateEventHash(eventData) {
|
|
13
|
+
const { eventId, timestamp, createdAt, ...hashableData } = eventData;
|
|
14
|
+
const hmac = (0, crypto_1.createHmac)('sha256', this.hmacSecret);
|
|
15
|
+
return hmac.update(JSON.stringify(hashableData)).digest('hex');
|
|
16
|
+
}
|
|
17
|
+
async isDuplicate(event, consumerGroupName) {
|
|
18
|
+
if (event.data === null)
|
|
19
|
+
return false;
|
|
20
|
+
const eventHash = this.calculateEventHash(event);
|
|
21
|
+
const key = `processed:${consumerGroupName}:${eventHash}`;
|
|
22
|
+
const result = await this.redisClient.set(key, '1', 'EX', this.ttl, 'NX');
|
|
23
|
+
const isDuplicate = result === null;
|
|
24
|
+
if (isDuplicate) {
|
|
25
|
+
logger_1.PUBLISHER_LOGGER.log(`Duplicate event detected for consumer group ${consumerGroupName}`);
|
|
26
|
+
}
|
|
27
|
+
return isDuplicate;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.ContentBasedDeduplication = ContentBasedDeduplication;
|
|
@@ -59,7 +59,7 @@ class ScheduledProcessor {
|
|
|
59
59
|
// Publish the event to each consumer group's stream
|
|
60
60
|
const streamName = `${eventData.eventName}:${consumerGroup}`;
|
|
61
61
|
const generatedKey = await this.redisPublisher
|
|
62
|
-
.xadd(streamName,
|
|
62
|
+
.xadd(streamName, key, 'data', JSON.stringify(eventData))
|
|
63
63
|
.catch((e) => logger_1.PUBLISHER_LOGGER.error(`PUBLISHER: Publishing event ${eventData.eventName} to consumer groups: ${consumerGroups.join(', ')} failed with data ${JSON.stringify(eventData)}, ${e} `));
|
|
64
64
|
if (key === '*')
|
|
65
65
|
key = generatedKey ?? key;
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import {
|
|
2
|
+
import { IAggregatedMetrics, TQueryableMetrics } from '../monitoring/types';
|
|
3
|
+
import { CircuitState } from '../performance/circuit_breaker';
|
|
4
|
+
import { EventData, IListenOptions, IStreamsConfig, PublishData } from './types';
|
|
3
5
|
export declare class Streams {
|
|
4
6
|
private _redisPublisher?;
|
|
5
7
|
private _redisGroups?;
|
|
8
|
+
private config;
|
|
9
|
+
private dlq;
|
|
10
|
+
private metricsCollector;
|
|
6
11
|
private consumerGroupName;
|
|
7
12
|
private instanceId;
|
|
8
13
|
private instanceUniqueId;
|
|
9
14
|
private cleanUpTimer;
|
|
10
15
|
private eventsListened;
|
|
16
|
+
private subscriptions;
|
|
17
|
+
private duplicateChecker;
|
|
18
|
+
private circuitBreaker;
|
|
11
19
|
private get redisPublisher();
|
|
12
20
|
private get redisGroups();
|
|
21
|
+
private DEFAULT_STREAMS_CONFIG;
|
|
13
22
|
/**
|
|
14
23
|
* Creates a new Streams instance for a given service.
|
|
15
24
|
*
|
|
@@ -24,7 +33,8 @@ export declare class Streams {
|
|
|
24
33
|
* // Create a new Streams instance for the "POS" service
|
|
25
34
|
* const streams = new Streams('POS');
|
|
26
35
|
*/
|
|
27
|
-
constructor(serviceName: string);
|
|
36
|
+
constructor(serviceName: string, config?: Partial<IStreamsConfig>);
|
|
37
|
+
private setupCircuitBreakerListeners;
|
|
28
38
|
private runClear;
|
|
29
39
|
/**
|
|
30
40
|
* Publishes an event with the given data to the Redis event stream.
|
|
@@ -96,7 +106,7 @@ export declare class Streams {
|
|
|
96
106
|
* PUBLISHER_LOGGER.log('New order created:', event.data);
|
|
97
107
|
* });
|
|
98
108
|
*/
|
|
99
|
-
listen<T = unknown, const TName extends string = string>(eventName: TName,
|
|
109
|
+
listen<T = unknown, const TName extends string = string>(eventName: TName, listenerOptions?: IListenOptions<T>): Observable<EventData<T, TName>>;
|
|
100
110
|
private createConsumerAndRegister;
|
|
101
111
|
private listenInternals;
|
|
102
112
|
/**
|
|
@@ -142,4 +152,52 @@ export declare class Streams {
|
|
|
142
152
|
}[];
|
|
143
153
|
message: string;
|
|
144
154
|
}>;
|
|
155
|
+
private logPerformance;
|
|
156
|
+
/**
|
|
157
|
+
* @description
|
|
158
|
+
* This method is use to retry an event that has ended in the dead letter queue,
|
|
159
|
+
* which happens after the first retry.
|
|
160
|
+
*/
|
|
161
|
+
retryFromDLQ(eventId: string): Promise<boolean>;
|
|
162
|
+
/**
|
|
163
|
+
* @description
|
|
164
|
+
* This returns the number of items and the rate at which events are added
|
|
165
|
+
* to the queue. The queue is global and hence remains as is
|
|
166
|
+
*/
|
|
167
|
+
getDLQStats(): Promise<{
|
|
168
|
+
size: number;
|
|
169
|
+
additionRate: number;
|
|
170
|
+
}>;
|
|
171
|
+
private removeSubscription;
|
|
172
|
+
/**
|
|
173
|
+
* @description
|
|
174
|
+
* This is a simple helper utility that can be used externally to create alerts based
|
|
175
|
+
* on thresholds that can be provided into the function. It returns true/false for each
|
|
176
|
+
* key that is provided. Not all keys are required
|
|
177
|
+
*/
|
|
178
|
+
checkThresholds(thresholds: Partial<TQueryableMetrics>): Promise<Record<string, boolean>>;
|
|
179
|
+
/**
|
|
180
|
+
* @description
|
|
181
|
+
* This will return you the stats of the publisher for the last 6 hours after cleaning
|
|
182
|
+
*/
|
|
183
|
+
getMetrics(startTime: number, endTime: number): Promise<IAggregatedMetrics[]>;
|
|
184
|
+
/**
|
|
185
|
+
* @description
|
|
186
|
+
* This will return you the latest stats of the publisher
|
|
187
|
+
*/
|
|
188
|
+
getLatestMetrics(): Promise<IAggregatedMetrics | null>;
|
|
189
|
+
/**
|
|
190
|
+
* @description
|
|
191
|
+
* This returns the status of the performance control setup. This includes
|
|
192
|
+
* the circuit breaker
|
|
193
|
+
*/
|
|
194
|
+
getPerformanceControlStatus(): Promise<{
|
|
195
|
+
circuitBreakerState: CircuitState;
|
|
196
|
+
}>;
|
|
197
|
+
/**
|
|
198
|
+
* @description
|
|
199
|
+
* This is a manual control to process stored events in case the
|
|
200
|
+
* circuit is OPEN
|
|
201
|
+
*/
|
|
202
|
+
processStoredEvents(): Promise<void>;
|
|
145
203
|
}
|