@jetit/publisher 1.0.2 → 1.0.3
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/index.d.ts +222 -0
- package/index.js +553 -0
- package/package.json +1 -1
- package/src/index.d.ts +0 -1
- package/src/index.js +0 -4
- package/src/lib/publisher.d.ts +0 -3
- package/src/lib/publisher.js +0 -9
- package/src/lib/redis/groups.d.ts +0 -2
- package/src/lib/redis/groups.js +0 -11
- package/src/lib/redis/registry.d.ts +0 -20
- package/src/lib/redis/registry.js +0 -57
- package/src/lib/redis/scheduler.d.ts +0 -15
- package/src/lib/redis/scheduler.js +0 -80
- package/src/lib/redis/streams.d.ts +0 -152
- package/src/lib/redis/streams.js +0 -392
- package/src/lib/redis/types.d.ts +0 -15
- package/src/lib/redis/types.js +0 -2
package/index.d.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
declare module "src/lib/redis/types" {
|
|
2
|
+
export type EventData<T> = {
|
|
3
|
+
data: T;
|
|
4
|
+
eventName: string;
|
|
5
|
+
eventId?: string;
|
|
6
|
+
};
|
|
7
|
+
export type PendingMessages = [never, never, string, string, Array<[string, number]>];
|
|
8
|
+
export type ClaimedMessages = Array<[never, string]>;
|
|
9
|
+
import { ClusterNode, ClusterOptions, RedisOptions } from 'ioredis';
|
|
10
|
+
export interface IOptions {
|
|
11
|
+
redis?: RedisOptions;
|
|
12
|
+
cluster?: {
|
|
13
|
+
options: ClusterOptions;
|
|
14
|
+
nodes: Array<ClusterNode>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
declare module "src/lib/redis/registry" {
|
|
19
|
+
import Redis, { Cluster } from 'ioredis';
|
|
20
|
+
import { IOptions } from "src/lib/redis/types";
|
|
21
|
+
export type RedisType = Redis | Cluster;
|
|
22
|
+
export class RedisRegistry {
|
|
23
|
+
private static registry;
|
|
24
|
+
private static options;
|
|
25
|
+
static attemptConnection(connectionKey: string, storeRef?: number): Redis;
|
|
26
|
+
static getConnection(connectionType?: string, storeRef?: number): RedisType;
|
|
27
|
+
static setOptions(options: IOptions): void;
|
|
28
|
+
static _getOptions(): IOptions;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* This function is used to set Redis Connection options per instance. If no
|
|
32
|
+
* options are provided, then the service connects as to a single instance
|
|
33
|
+
* with the environment values from REDIS_PORT and REDIS_HOST. if those
|
|
34
|
+
* environment values are not provided, it attempts to connect to localhost:6379
|
|
35
|
+
*
|
|
36
|
+
* @param options
|
|
37
|
+
*/
|
|
38
|
+
export function setRedisConnectionSettings(options: IOptions): void;
|
|
39
|
+
}
|
|
40
|
+
declare module "src/lib/redis/groups" {
|
|
41
|
+
import { RedisType } from "src/lib/redis/registry";
|
|
42
|
+
export function getAllConsumerGroups(eventName: string, redisConnection: RedisType): Promise<string[]>;
|
|
43
|
+
}
|
|
44
|
+
declare module "src/lib/redis/streams" {
|
|
45
|
+
import { RedisType } from "src/lib/redis/registry";
|
|
46
|
+
import { EventData } from "src/lib/redis/types";
|
|
47
|
+
import { Observable } from 'rxjs';
|
|
48
|
+
export class Streams {
|
|
49
|
+
private _redisPublisher?;
|
|
50
|
+
private _redisSubscriber?;
|
|
51
|
+
private _redisGroups?;
|
|
52
|
+
private consumerGroupName;
|
|
53
|
+
private instanceId;
|
|
54
|
+
private cleanUpTimer;
|
|
55
|
+
private eventsListened;
|
|
56
|
+
get redisPublisher(): RedisType;
|
|
57
|
+
get redisSubscriber(): RedisType;
|
|
58
|
+
get redisGroups(): RedisType;
|
|
59
|
+
/**
|
|
60
|
+
* Creates a new Streams instance for a given service.
|
|
61
|
+
*
|
|
62
|
+
* The constructor initializes the Redis connections for publishers, subscribers, and consumer groups.
|
|
63
|
+
* It also sets up an interval timer for clearing expired messages from Redis and another interval timer
|
|
64
|
+
* for processing scheduled events at regular intervals.
|
|
65
|
+
*
|
|
66
|
+
* @param serviceName - A unique name for the service that will be using this Streams instance.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
*
|
|
70
|
+
* // Create a new Streams instance for the "POS" service
|
|
71
|
+
* const streams = new Streams('POS');
|
|
72
|
+
*/
|
|
73
|
+
constructor(serviceName: string);
|
|
74
|
+
private createConsumerGroup;
|
|
75
|
+
private isDuplicateMessage;
|
|
76
|
+
private clearDuplicationCheckKeys;
|
|
77
|
+
/**
|
|
78
|
+
* Publishes an event with the given data to the Redis event stream.
|
|
79
|
+
*
|
|
80
|
+
* The method generates a unique event ID for each event, and adds it to the event data to handle message
|
|
81
|
+
* deduplication.
|
|
82
|
+
*
|
|
83
|
+
* @param data - An EventData<T> object containing the data for the event.
|
|
84
|
+
*
|
|
85
|
+
* @returns A Promise that resolves when the event has been published to the Redis stream.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
*
|
|
89
|
+
* // Publish an "order.created" event with the given order data
|
|
90
|
+
* const orderData = { id: '123', customerName: 'John Doe', amount: 100 };
|
|
91
|
+
* const eventData = { eventName: 'order.created', data: orderData };
|
|
92
|
+
* await streams.publish(eventData);
|
|
93
|
+
*/
|
|
94
|
+
publish<T>(data: EventData<T>): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Schedules an event to be published at a specified future time. Thee event gets published if the
|
|
97
|
+
* differnece between the current time and the scheduled time is less than 500ms.
|
|
98
|
+
*
|
|
99
|
+
* @param scheduledTime - The Date object representing the future time when the event should be published.
|
|
100
|
+
* @param eventData - The event data object, containing the event name and its associated data.
|
|
101
|
+
*
|
|
102
|
+
* @throws Error - Throws an error if the scheduled time is in the past.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
*
|
|
106
|
+
* const streams = new Streams('app-service');
|
|
107
|
+
*
|
|
108
|
+
* const futureTime = new Date(Date.now() + 10000); // 10 seconds from now
|
|
109
|
+
* const eventData: EventData<string> = {
|
|
110
|
+
* eventName: 'order.created',
|
|
111
|
+
* data: 'Order data'
|
|
112
|
+
* };
|
|
113
|
+
*
|
|
114
|
+
* await streams.scheduledPublish(futureTime, eventData);
|
|
115
|
+
*/
|
|
116
|
+
scheduledPublish<T>(scheduledTime: Date, eventData: EventData<T>, uniquePerInstance?: boolean): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Listens for events with the given name and returns an Observable that emits an EventData<T> object
|
|
119
|
+
* each time a new event is received.
|
|
120
|
+
*
|
|
121
|
+
* The method uses a BehaviorSubject to emit the events as Observables. The BehaviorSubject ensures
|
|
122
|
+
* that new subscribers receive the last emitted event, even if they subscribe after the event has been emitted.
|
|
123
|
+
*
|
|
124
|
+
* If an error occurs while subscribing, the method logs the error to the console and throws
|
|
125
|
+
* an error. This is done to prevent the service from continuing without a proper event subscription.
|
|
126
|
+
*
|
|
127
|
+
* There is retry logic with exponential backoff to handle error cases. These are also controllable by the
|
|
128
|
+
* calling service
|
|
129
|
+
*
|
|
130
|
+
* @param eventName - The name of the event to listen for.
|
|
131
|
+
*
|
|
132
|
+
* @returns An Observable that emits an EventData<T> object each time a new event is received.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
*
|
|
136
|
+
* // Listen for "order.created" events
|
|
137
|
+
* const orderCreated = streams.listen<OrderCreatedEvent>('order.created');
|
|
138
|
+
*
|
|
139
|
+
* // Subscribe to the Observable and log each new event
|
|
140
|
+
* orderCreated.subscribe((event) => {
|
|
141
|
+
* console.log('New order created:', event.data);
|
|
142
|
+
* });
|
|
143
|
+
*/
|
|
144
|
+
listen<T>(eventName: string, maxRetries?: number, initialDelay?: number): Observable<EventData<T>>;
|
|
145
|
+
private listenInternals;
|
|
146
|
+
/**
|
|
147
|
+
* This method takes all messages allocated to this instance and republishes them so
|
|
148
|
+
* that other instances of this service can receive and process them.
|
|
149
|
+
*
|
|
150
|
+
* This needs to be handled every 1-2 minutes if the queue becomes too long and messages
|
|
151
|
+
* are not being processed.
|
|
152
|
+
*
|
|
153
|
+
* Ideal implementation would be to wrap this inside a setInterval
|
|
154
|
+
* @param streamName
|
|
155
|
+
*/
|
|
156
|
+
republishUnprocessedEvents(eventName: string): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* This method is used to claim messages in the event of a service crash. This library currently
|
|
159
|
+
* does not detect a service crash. This needs to be built as an extension of Kubernetes and
|
|
160
|
+
* a standalone service that notifies this service to process the events that are marked as
|
|
161
|
+
* pending
|
|
162
|
+
*
|
|
163
|
+
* @param streamName
|
|
164
|
+
* @param idleTimeout
|
|
165
|
+
*
|
|
166
|
+
* * @example
|
|
167
|
+
*
|
|
168
|
+
* // Attempt to recover messages from the "order.created" stream with an idle timeout of 10 seconds
|
|
169
|
+
* await streams.recoverCrashedConsumerMessages('order.created', 10000);
|
|
170
|
+
*/
|
|
171
|
+
recoverCrashedConsumerMessages(eventName: string, idleTimeout: number): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* This method allows the possibility of a graceful shutdown by cleaning up the
|
|
174
|
+
* redis connections.
|
|
175
|
+
*
|
|
176
|
+
* In all services where the library is used, its better to implement this method
|
|
177
|
+
*
|
|
178
|
+
* process.on('SIGTERM', shutdown);
|
|
179
|
+
* process.on('SIGINT', shutdown);
|
|
180
|
+
*
|
|
181
|
+
* async function shutdown(): Promise<void> {
|
|
182
|
+
* console.log('Graceful shutdown initiated.');
|
|
183
|
+
* try {
|
|
184
|
+
* await streams.close();
|
|
185
|
+
* console.log('Resources and connections successfully closed.');
|
|
186
|
+
* } catch (error) {
|
|
187
|
+
* console.error('Error during graceful shutdown:', error);
|
|
188
|
+
* }
|
|
189
|
+
* process.exit(0);
|
|
190
|
+
* }
|
|
191
|
+
*/
|
|
192
|
+
close(): Promise<void>;
|
|
193
|
+
private clearSubscribedEvents;
|
|
194
|
+
private registerConsumerGroup;
|
|
195
|
+
private cleanupAcknowledgedMessages;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
declare module "src/lib/redis/scheduler" {
|
|
199
|
+
import { RedisType } from "src/lib/redis/registry";
|
|
200
|
+
/**
|
|
201
|
+
* DO NOT USE THIS CLASS IF YOU DON'T KNOW WHAT YOU ARE DOING. This class is
|
|
202
|
+
* meant to be used internally by the scheduler application
|
|
203
|
+
*/
|
|
204
|
+
export class ScheduledProcessor {
|
|
205
|
+
private scheduledMessagesTimer;
|
|
206
|
+
private _redisPublisher?;
|
|
207
|
+
private previousTaskCompleted;
|
|
208
|
+
get redisPublisher(): RedisType;
|
|
209
|
+
constructor(duration?: number);
|
|
210
|
+
private processScheduledEvents;
|
|
211
|
+
getAllScheduledEvents(): Promise<Array<string>>;
|
|
212
|
+
close(): Promise<void>;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
declare module "src/lib/publisher" {
|
|
216
|
+
export { Streams as Publisher } from "src/lib/redis/streams";
|
|
217
|
+
export { setRedisConnectionSettings as setRedisConfig } from "src/lib/redis/registry";
|
|
218
|
+
export { ScheduledProcessor as __SCHEDULER_INTERNALS__ } from "src/lib/redis/scheduler";
|
|
219
|
+
}
|
|
220
|
+
declare module "src/index" {
|
|
221
|
+
export * from "src/lib/publisher";
|
|
222
|
+
}
|