@kaapi/kafka-messaging 0.0.39 → 0.0.41
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/CHANGELOG.md +48 -0
- package/README.md +195 -38
- package/lib/index.d.ts +279 -10
- package/lib/index.js +426 -68
- package/lib/index.js.map +1 -1
- package/package.json +7 -3
package/lib/index.d.ts
CHANGED
|
@@ -1,18 +1,92 @@
|
|
|
1
1
|
import { Admin, AdminConfig, Consumer, ConsumerConfig, ITopicConfig, Kafka, KafkaConfig, Producer, ProducerConfig } from 'kafkajs';
|
|
2
2
|
import { ILogger, IMessaging, IMessagingContext } from '@kaapi/kaapi';
|
|
3
|
+
/**
|
|
4
|
+
* Extended messaging context with Kafka-specific metadata.
|
|
5
|
+
*/
|
|
3
6
|
export interface KafkaMessagingContext extends IMessagingContext {
|
|
7
|
+
/** The Kafka message offset */
|
|
4
8
|
offset?: string;
|
|
9
|
+
address?: string;
|
|
5
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for KafkaMessaging.
|
|
13
|
+
* Extends KafkaJS's KafkaConfig with additional Kaapi-specific options.
|
|
14
|
+
*/
|
|
6
15
|
export interface KafkaMessagingConfig extends KafkaConfig {
|
|
16
|
+
/** Optional logger implementing Kaapi's ILogger interface */
|
|
7
17
|
logger?: ILogger;
|
|
18
|
+
/** Optional unique service address for routing and identification */
|
|
8
19
|
address?: string;
|
|
20
|
+
/** Optional human-readable name for service tracking/monitoring */
|
|
9
21
|
name?: string;
|
|
22
|
+
/** Optional default KafkaJS producer configuration */
|
|
10
23
|
producer?: ProducerConfig;
|
|
11
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Configuration options for subscribing to a Kafka topic.
|
|
27
|
+
* Extends KafkaJS's ConsumerConfig with additional options.
|
|
28
|
+
*/
|
|
12
29
|
export interface KafkaMessagingSubscribeConfig extends Partial<ConsumerConfig> {
|
|
30
|
+
/** Whether to start consuming from the beginning of the topic */
|
|
13
31
|
fromBeginning?: boolean;
|
|
32
|
+
/** Callback invoked when the consumer is ready */
|
|
14
33
|
onReady?(consumer: Consumer): void;
|
|
34
|
+
/**
|
|
35
|
+
* Custom consumer group ID. If not provided, defaults to `{name}.{topic}`
|
|
36
|
+
* where `name` is the service name from KafkaMessagingConfig.
|
|
37
|
+
*/
|
|
38
|
+
groupId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Prefix for the auto-generated group ID. Only used when `groupId` is not provided.
|
|
41
|
+
* Defaults to the service `name` or 'group' if name is not set.
|
|
42
|
+
*/
|
|
43
|
+
groupIdPrefix?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether to log partition offsets on subscribe.
|
|
46
|
+
* Requires an admin client connection, adding some overhead.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
logOffsets?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Called when a message handler throws an error.
|
|
52
|
+
* Allows custom error handling (e.g., alerting, metrics, logging to external service).
|
|
53
|
+
*
|
|
54
|
+
* @param error - The error thrown by the handler
|
|
55
|
+
* @param message - The parsed message that failed
|
|
56
|
+
* @param context - The message context (offset, headers, etc.)
|
|
57
|
+
*/
|
|
58
|
+
onError?(error: unknown, message: unknown, context: KafkaMessagingContext): void | Promise<void>;
|
|
15
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* A message to be published in a batch.
|
|
62
|
+
*/
|
|
63
|
+
export interface KafkaMessagingBatchMessage<T = unknown> {
|
|
64
|
+
/** The message payload */
|
|
65
|
+
value: T;
|
|
66
|
+
/** Optional message key for partitioning */
|
|
67
|
+
key?: string;
|
|
68
|
+
/** Optional partition to send to */
|
|
69
|
+
partition?: number;
|
|
70
|
+
/** Optional custom headers (merged with default headers) */
|
|
71
|
+
headers?: Record<string, string>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A lightweight wrapper around KafkaJS that integrates with the Kaapi framework
|
|
75
|
+
* to provide a clean and consistent message publishing and consuming interface.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const messaging = new KafkaMessaging({
|
|
80
|
+
* clientId: 'my-app',
|
|
81
|
+
* brokers: ['localhost:9092'],
|
|
82
|
+
* name: 'my-service',
|
|
83
|
+
* address: 'service-1'
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* await messaging.publish('my-topic', { event: 'user.created' });
|
|
87
|
+
* await messaging.subscribe('my-topic', (msg, ctx) => console.log(msg));
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
16
90
|
export declare class KafkaMessaging implements IMessaging {
|
|
17
91
|
#private;
|
|
18
92
|
protected kafka?: Kafka;
|
|
@@ -21,10 +95,66 @@ export declare class KafkaMessaging implements IMessaging {
|
|
|
21
95
|
protected currentProducerId?: string;
|
|
22
96
|
get activeConsumers(): ReadonlySet<Consumer>;
|
|
23
97
|
get activeProducers(): ReadonlySet<Producer>;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new KafkaMessaging instance.
|
|
100
|
+
*
|
|
101
|
+
* @param arg - Configuration options for the Kafka client
|
|
102
|
+
*/
|
|
24
103
|
constructor(arg: KafkaMessagingConfig);
|
|
25
104
|
private _createInstance;
|
|
105
|
+
/**
|
|
106
|
+
* Internal method to initialize the shared admin.
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
private _initializeSharedAdmin;
|
|
110
|
+
/**
|
|
111
|
+
* Internal method to initialize the producer.
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
private _initializeProducer;
|
|
26
115
|
protected getKafka(): Kafka | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Gets or creates a shared admin instance for internal operations.
|
|
118
|
+
* Uses lazy initialization to avoid unnecessary connections.
|
|
119
|
+
*
|
|
120
|
+
* @returns A promise that resolves to the shared admin instance
|
|
121
|
+
*/
|
|
122
|
+
protected getSharedAdmin(): Promise<Admin | undefined>;
|
|
123
|
+
/**
|
|
124
|
+
* Creates and connects a Kafka admin client.
|
|
125
|
+
* The admin client is automatically tracked and will be disconnected during shutdown.
|
|
126
|
+
*
|
|
127
|
+
* @param config - Optional admin client configuration
|
|
128
|
+
* @returns A promise that resolves to the connected admin client, or undefined if Kafka is unavailable
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const admin = await messaging.createAdmin();
|
|
133
|
+
* const topics = await admin?.listTopics();
|
|
134
|
+
* await admin?.disconnect();
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
27
137
|
createAdmin(config?: AdminConfig): Promise<Admin | undefined>;
|
|
138
|
+
/**
|
|
139
|
+
* Creates a new Kafka topic with the specified configuration.
|
|
140
|
+
*
|
|
141
|
+
* @param topic - The topic configuration including name, partitions, and replication factor
|
|
142
|
+
* @param config - Optional creation options
|
|
143
|
+
* @param config.validateOnly - If true, only validates the request without creating the topic
|
|
144
|
+
* @param config.waitForLeaders - If true, waits for partition leaders to be elected
|
|
145
|
+
* @param config.timeout - Timeout in milliseconds for the operation
|
|
146
|
+
*
|
|
147
|
+
* @throws {Error} If the admin client cannot be created
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* await messaging.createTopic({
|
|
152
|
+
* topic: 'my-topic',
|
|
153
|
+
* numPartitions: 3,
|
|
154
|
+
* replicationFactor: 1
|
|
155
|
+
* }, { waitForLeaders: true });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
28
158
|
createTopic(topic: ITopicConfig, config?: {
|
|
29
159
|
validateOnly?: boolean;
|
|
30
160
|
waitForLeaders?: boolean;
|
|
@@ -46,32 +176,163 @@ export declare class KafkaMessaging implements IMessaging {
|
|
|
46
176
|
*/
|
|
47
177
|
waitForTopicReady(topic: string, timeoutMs?: number, checkIntervalMs?: number): Promise<void>;
|
|
48
178
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* @
|
|
179
|
+
* Fetches and logs partition offsets for a topic.
|
|
180
|
+
* Uses the shared admin instance to minimize connections.
|
|
181
|
+
*
|
|
182
|
+
* @param topic - The topic to fetch offsets for
|
|
183
|
+
* @returns The partition offset information, or undefined if unavailable
|
|
184
|
+
*/
|
|
185
|
+
fetchTopicOffsets(topic: string): Promise<Array<{
|
|
186
|
+
partition: number;
|
|
187
|
+
offset: string;
|
|
188
|
+
high: string;
|
|
189
|
+
low: string;
|
|
190
|
+
}> | undefined>;
|
|
191
|
+
/**
|
|
192
|
+
* Creates and connects a new Kafka consumer.
|
|
193
|
+
* The consumer is automatically tracked and will be disconnected during shutdown.
|
|
194
|
+
*
|
|
195
|
+
* @param groupId - The consumer group ID
|
|
196
|
+
* @param config - Optional consumer configuration overrides
|
|
197
|
+
* @returns A promise that resolves to the connected consumer, or undefined if Kafka is unavailable
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const consumer = await messaging.createConsumer('my-group', {
|
|
202
|
+
* sessionTimeout: 30000
|
|
203
|
+
* });
|
|
204
|
+
* ```
|
|
53
205
|
*/
|
|
54
206
|
createConsumer(groupId: string, config?: Partial<ConsumerConfig>): Promise<Consumer | undefined>;
|
|
55
207
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
208
|
+
* Creates and connects a new Kafka producer.
|
|
209
|
+
* The producer is automatically tracked and will be disconnected during shutdown.
|
|
210
|
+
*
|
|
211
|
+
* @param config - Optional producer configuration overrides
|
|
212
|
+
* @returns A promise that resolves to the connected producer, or undefined if Kafka is unavailable
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* const producer = await messaging.createProducer({
|
|
217
|
+
* idempotent: true
|
|
218
|
+
* });
|
|
219
|
+
* ```
|
|
59
220
|
*/
|
|
60
221
|
createProducer(config?: Partial<ProducerConfig>): Promise<Producer | undefined>;
|
|
61
222
|
/**
|
|
62
|
-
*
|
|
223
|
+
* Gets or creates the singleton producer instance.
|
|
224
|
+
* Uses a promise-based lock to prevent race conditions when called concurrently.
|
|
225
|
+
*
|
|
226
|
+
* @returns A promise that resolves to the producer instance, or undefined if unavailable.
|
|
63
227
|
*/
|
|
64
228
|
getProducer(): Promise<Producer | undefined>;
|
|
65
229
|
/**
|
|
66
|
-
*
|
|
230
|
+
* Disconnects the singleton producer instance.
|
|
231
|
+
*
|
|
232
|
+
* @returns A promise that resolves when the producer is disconnected
|
|
67
233
|
*/
|
|
68
234
|
disconnectProducer(): Promise<void>;
|
|
235
|
+
/**
|
|
236
|
+
* Publishes multiple messages to a Kafka topic in a single batch.
|
|
237
|
+
* More efficient than multiple `publish()` calls for high-throughput scenarios.
|
|
238
|
+
*
|
|
239
|
+
* @typeParam T - The type of the message payload
|
|
240
|
+
* @param topic - The Kafka topic to publish to
|
|
241
|
+
* @param messages - Array of messages to publish
|
|
242
|
+
*
|
|
243
|
+
* @throws {Error} If the batch fails to send
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```ts
|
|
247
|
+
* await messaging.publishBatch('user-events', [
|
|
248
|
+
* { value: { event: 'user.created', userId: '1' } },
|
|
249
|
+
* { value: { event: 'user.created', userId: '2' } },
|
|
250
|
+
* { value: { event: 'user.updated', userId: '3' }, key: 'user-3' },
|
|
251
|
+
* ]);
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
publishBatch<T = unknown>(topic: string, messages: KafkaMessagingBatchMessage<T>[]): Promise<void>;
|
|
255
|
+
/**
|
|
256
|
+
* Publishes a message to the specified Kafka topic.
|
|
257
|
+
* Automatically manages the producer lifecycle and includes service metadata in headers.
|
|
258
|
+
*
|
|
259
|
+
* @typeParam T - The type of the message payload
|
|
260
|
+
* @param topic - The Kafka topic to publish to
|
|
261
|
+
* @param message - The message payload (will be JSON serialized)
|
|
262
|
+
*
|
|
263
|
+
* @throws {Error} If the message fails to send
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* await messaging.publish('user-events', {
|
|
268
|
+
* event: 'user.created',
|
|
269
|
+
* userId: '123',
|
|
270
|
+
* timestamp: Date.now()
|
|
271
|
+
* });
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
69
274
|
publish<T = unknown>(topic: string, message: T): Promise<void>;
|
|
70
275
|
/**
|
|
71
|
-
*
|
|
276
|
+
* Subscribes to a Kafka topic and processes messages with the provided handler.
|
|
277
|
+
* Creates a new consumer for each subscription with an auto-generated group ID.
|
|
278
|
+
*
|
|
279
|
+
* @typeParam T - The expected type of incoming messages
|
|
280
|
+
* @param topic - The Kafka topic to subscribe to
|
|
281
|
+
* @param handler - Callback function invoked for each message. Can be async.
|
|
282
|
+
* @param config - Optional subscription configuration
|
|
283
|
+
* @param config.fromBeginning - Start consuming from the beginning of the topic
|
|
284
|
+
* @param config.onReady - Callback invoked when the consumer is ready
|
|
285
|
+
* @param config.groupId - Override the auto-generated consumer group ID
|
|
286
|
+
* @param config.groupIdPrefix - Prefix for auto-generated group ID (default: service name)
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* // Using auto-generated group ID (e.g., "my-service.user-events")
|
|
291
|
+
* await messaging.subscribe('user-events', handler);
|
|
292
|
+
*
|
|
293
|
+
* // Using custom group ID
|
|
294
|
+
* await messaging.subscribe('user-events', handler, {
|
|
295
|
+
* groupId: 'my-custom-consumer-group'
|
|
296
|
+
* });
|
|
297
|
+
*
|
|
298
|
+
* // Using custom prefix (e.g., "analytics.user-events")
|
|
299
|
+
* await messaging.subscribe('user-events', handler, {
|
|
300
|
+
* groupIdPrefix: 'analytics'
|
|
301
|
+
* });
|
|
302
|
+
*
|
|
303
|
+
* // With offset logging enabled
|
|
304
|
+
* await messaging.subscribe('user-events', handler, {
|
|
305
|
+
* logOffsets: true
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
72
308
|
*/
|
|
73
309
|
subscribe<T = unknown>(topic: string, handler: (message: T, context: KafkaMessagingContext) => Promise<void> | void, config?: KafkaMessagingSubscribeConfig): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Safely disconnects a Kafka client with timeout protection.
|
|
312
|
+
* Prevents hanging if the client fails to disconnect gracefully.
|
|
313
|
+
*
|
|
314
|
+
* @param client - The Kafka client (producer, consumer, or admin) to disconnect
|
|
315
|
+
* @param timeoutMs - Maximum time to wait for disconnection (default: 5000ms)
|
|
316
|
+
* @returns A promise that resolves when disconnected or rejects on timeout
|
|
317
|
+
*
|
|
318
|
+
* @throws {Error} If the disconnect times out
|
|
319
|
+
*/
|
|
74
320
|
safeDisconnect(client: Producer | Consumer | Admin, timeoutMs?: number): Promise<unknown>;
|
|
321
|
+
/**
|
|
322
|
+
* Gracefully shuts down all tracked Kafka clients (producers, consumers, and admins).
|
|
323
|
+
* Should be called during application teardown to release resources.
|
|
324
|
+
*
|
|
325
|
+
* @returns A summary of the shutdown operation including success and error counts
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* process.on('SIGTERM', async () => {
|
|
330
|
+
* const result = await messaging.shutdown();
|
|
331
|
+
* console.log(`Shutdown complete: ${result.successProducers} producers, ${result.errorCount} errors`);
|
|
332
|
+
* process.exit(0);
|
|
333
|
+
* });
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
75
336
|
shutdown(): Promise<{
|
|
76
337
|
successProducers: number;
|
|
77
338
|
successConsumers: number;
|
|
@@ -79,4 +340,12 @@ export declare class KafkaMessaging implements IMessaging {
|
|
|
79
340
|
errorCount: number;
|
|
80
341
|
}>;
|
|
81
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Safely disconnects a Kafka client with timeout protection.
|
|
345
|
+
* Standalone utility function.
|
|
346
|
+
*
|
|
347
|
+
* @param client - The Kafka client to disconnect
|
|
348
|
+
* @param timeoutMs - Maximum time to wait (default: 5000ms)
|
|
349
|
+
* @returns A promise that resolves when disconnected or rejects on timeout
|
|
350
|
+
*/
|
|
82
351
|
export declare function safeDisconnect(client: Producer | Consumer | Admin, timeoutMs?: number): Promise<unknown>;
|