@kaapi/kafka-messaging 0.0.13 → 0.0.15
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 +247 -2
- package/lib/index.d.ts +57 -5
- package/lib/index.js +220 -25
- package/lib/index.js.map +1 -1
- package/package.json +5 -2
- package/test/kafka-messaging.spec.ts +129 -0
package/README.md
CHANGED
|
@@ -1,3 +1,248 @@
|
|
|
1
|
-
# @kaapi/kafka-messaging
|
|
1
|
+
# 📦 @kaapi/kafka-messaging
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@kaapi/kafka-messaging` is a lightweight wrapper around [`kafkajs`](https://github.com/tulios/kafkajs) that integrates with the [`Kaapi`](https://github.com/demingongo/kaapi) framework to provide a clean and consistent **message publishing and consuming interface**.
|
|
4
|
+
|
|
5
|
+
It abstracts Kafka’s producer/consumer logic and provides a simple interface to:
|
|
6
|
+
|
|
7
|
+
* ✅ Publish messages
|
|
8
|
+
* ✅ Subscribe to topics
|
|
9
|
+
* ✅ Support structured logging via Kaapi's logger
|
|
10
|
+
* ✅ Handle offsets and message metadata
|
|
11
|
+
* ✅ Reuse Kafka producers/consumers
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✨ Features
|
|
16
|
+
|
|
17
|
+
* Simple `publish(topic, message)` API
|
|
18
|
+
* Flexible `subscribe(topic, handler, config)` with offset tracking
|
|
19
|
+
* KafkaJS-compatible configuration
|
|
20
|
+
* Structured logging via Kaapi’s `ILogger`
|
|
21
|
+
* Typed message handling with TypeScript
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🚀 Getting Started with KafkaMessaging
|
|
26
|
+
|
|
27
|
+
This guide walks you through setting up and using the `KafkaMessaging` class to publish and consume messages with Apache Kafka.
|
|
28
|
+
|
|
29
|
+
### Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @kaapi/kafka-messaging kafkajs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### Basic Setup
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { KafkaMessaging } from '@kaapi/kafka-messaging';
|
|
41
|
+
|
|
42
|
+
const messaging = new KafkaMessaging({
|
|
43
|
+
clientId: 'my-app',
|
|
44
|
+
brokers: ['localhost:9092'],
|
|
45
|
+
name: 'my-service',
|
|
46
|
+
address: 'service-1',
|
|
47
|
+
logger: createLogger() // optional, use Kaapi ILogger
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The constructor accepts a `KafkaMessagingConfig` object, which extends `KafkaConfig` from [kafkajs](https://kafka.js.org/):
|
|
52
|
+
|
|
53
|
+
| Option | Type | Description |
|
|
54
|
+
| ---------- | ---------------- | ------------------------------------------------------------------------- |
|
|
55
|
+
| `brokers` | `string[]` | List of Kafka broker addresses (e.g. `['localhost:9092']`). **Required.** |
|
|
56
|
+
| `clientId` | `string` | Unique client identifier for Kafka. |
|
|
57
|
+
| `logger` | `ILogger` | Optional logger implementing Kaapi's `ILogger` interface. |
|
|
58
|
+
| `address` | `string` | Optional unique service address for routing and identification. |
|
|
59
|
+
| `name` | `string` | Optional human-readable name for service tracking/monitoring. |
|
|
60
|
+
| `producer` | `ProducerConfig` | Optional default KafkaJS producer configuration. |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Creating a Topic
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
await messaging.createTopic({
|
|
68
|
+
topic: 'my-topic',
|
|
69
|
+
numPartitions: 1,
|
|
70
|
+
replicationFactor: 1,
|
|
71
|
+
}, {
|
|
72
|
+
waitForLeaders: true
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ensure the topic is ready before publishing
|
|
76
|
+
const timeoutMs = 10000;
|
|
77
|
+
const checkIntervalMs = 200;
|
|
78
|
+
await messaging.waitForTopicReady('my-topic', timeoutMs, checkIntervalMs);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### Publishing a Message
|
|
84
|
+
|
|
85
|
+
`publish(topic, message)` sends a message to a given Kafka topic.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
await messaging.publish('my-topic', {
|
|
89
|
+
userId: '123',
|
|
90
|
+
action: 'login',
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
* `topic`: The Kafka topic name
|
|
95
|
+
* `message`: Any serializable object
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### Subscribing to a Topic
|
|
100
|
+
|
|
101
|
+
`subscribe(topic, handler, config?)` subscribes to a Kafka topic and calls the provided handler on each message.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
await messaging.subscribe('my-topic', async (message, sender) => {
|
|
105
|
+
console.log('Received:', message);
|
|
106
|
+
console.log('From:', sender.name, sender.address);
|
|
107
|
+
console.log('Offset:', sender.offset);
|
|
108
|
+
}, {
|
|
109
|
+
fromBeginning: true
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
* `topic`: The Kafka topic name
|
|
114
|
+
* `handler`: `(message, sender) => void | Promise<void>`
|
|
115
|
+
* `config?`: `KafkaMessagingSubscribeConfig` (extends `ConsumerConfig`)
|
|
116
|
+
* `groupId?`: Kafka consumer group ID
|
|
117
|
+
* `fromBeginning?`: boolean - Start consuming from beginning of topic
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Graceful Shutdown
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
await messaging.shutdown();
|
|
125
|
+
```
|
|
126
|
+
This will disconnect all tracked producers, consumers, and admin clients safely.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🧱 Example Usage
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// messaging.ts
|
|
134
|
+
|
|
135
|
+
import { Kaapi, createLogger } from '@kaapi/kaapi'
|
|
136
|
+
import { KafkaMessaging } from '@kaapi/kafka-messaging';
|
|
137
|
+
|
|
138
|
+
const messaging = new KafkaMessaging({
|
|
139
|
+
clientId: 'my-app',
|
|
140
|
+
brokers: ['localhost:9092'],
|
|
141
|
+
name: 'my-service',
|
|
142
|
+
address: 'service-1'
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Initialize the Kaapi app with messaging
|
|
147
|
+
*/
|
|
148
|
+
const app = new Kaapi({
|
|
149
|
+
port: 3000,
|
|
150
|
+
host: 'localhost',
|
|
151
|
+
messaging,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Demonstrates how to subscribe and publish a message
|
|
156
|
+
*/
|
|
157
|
+
async function runExample(): Promise<void> {
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Option 1: Use Kaapi app (recommended in app lifecycle)
|
|
161
|
+
*/
|
|
162
|
+
// Publish a message
|
|
163
|
+
await app.publish('my-topic', { event: 'user.created', userId: 456 });
|
|
164
|
+
|
|
165
|
+
// Subscribe to messages
|
|
166
|
+
await app.subscribe('my-topic', async (message, sender) => {
|
|
167
|
+
console.log('Received:', message);
|
|
168
|
+
console.log('Offset:', sender.offset);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Option 2: Use messaging directly (standalone)
|
|
173
|
+
*/
|
|
174
|
+
// Publish a message
|
|
175
|
+
await messaging.publish('my-topic', { event: 'user.created', userId: 123 });
|
|
176
|
+
|
|
177
|
+
// Subscribe to messages
|
|
178
|
+
await messaging.subscribe('my-topic', async (message, sender) => {
|
|
179
|
+
console.log('Received:', message);
|
|
180
|
+
console.log('Offset:', sender.offset);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
runExample().catch((err) => {
|
|
185
|
+
console.error('❌ Messaging example failed:', err);
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Public API Contract
|
|
192
|
+
|
|
193
|
+
The `KafkaMessaging` class provides a safe and resilient interface for interacting with Kafka. Developers should use the following methods to ensure proper lifecycle management, resource tracking, and graceful shutdown.
|
|
194
|
+
|
|
195
|
+
### Public Methods
|
|
196
|
+
|
|
197
|
+
| Method | Purpose |
|
|
198
|
+
|-----------------------------------|-------------------------------------------------------------------------|
|
|
199
|
+
| `createProducer()` | Creates and connects a Kafka producer. Automatically tracked and cleaned up. |
|
|
200
|
+
| `createConsumer(groupId, config?)`| Creates and connects a Kafka consumer. Automatically tracked and cleaned up. |
|
|
201
|
+
| `createAdmin(config?)` | Creates and connects a Kafka admin client. Tracked for shutdown. |
|
|
202
|
+
| `publish(topic, message)` | Sends a message to the specified topic using the managed producer. |
|
|
203
|
+
| `subscribe(topic, handler, config?)` | Subscribes to a topic and processes messages with the given handler. |
|
|
204
|
+
| `shutdown()` | Gracefully disconnects all tracked producers, consumers, and admins. |
|
|
205
|
+
| `safeDisconnect(client, timeoutMs?)` | Disconnects a Kafka client with timeout protection. |
|
|
206
|
+
| `createTopic(topicConfig, options?)` | Creates a Kafka topic with optional validation and leader wait. |
|
|
207
|
+
| `waitForTopicReady(topic, timeoutMs?, checkIntervalMs?)` | Ensures the topic is ready. |
|
|
208
|
+
|
|
209
|
+
### Internal Methods (Not Public)
|
|
210
|
+
|
|
211
|
+
| Method | Status | Reason for Restriction |
|
|
212
|
+
|----------------|------------|-------------------------------------------------|
|
|
213
|
+
| `getKafka()` | Protected | Used internally to instantiate Kafka clients. Avoid direct access to prevent unmanaged connections. |
|
|
214
|
+
|
|
215
|
+
### Best Practices
|
|
216
|
+
|
|
217
|
+
- Always use `createProducer`, `createConsumer`, or `createAdmin` to ensure proper tracking.
|
|
218
|
+
- Avoid accessing the raw Kafka instance directly.
|
|
219
|
+
- Call `shutdown()` during application teardown to release resources.
|
|
220
|
+
- Use `createTopic()` and `waitForTopicReady()` in tests or dynamic topic scenarios.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 🛠️ Requirements
|
|
225
|
+
|
|
226
|
+
* Node.js 16+
|
|
227
|
+
* A running Kafka instance
|
|
228
|
+
* Optional: integrate into a [Kaapi](https://github.com/demingongo/kaapi) service lifecycle
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 📚 Related
|
|
233
|
+
|
|
234
|
+
* [KafkaJS](https://github.com/tulios/kafkajs) — the underlying Kafka client
|
|
235
|
+
* [Kaapi](https://github.com/demingongo/kaapi) — framework powering this abstraction
|
|
236
|
+
* [@kaapi/kaapi](https://www.npmjs.com/package/@kaapi/kaapi)
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 🧪 Testing
|
|
241
|
+
|
|
242
|
+
You can mock Kafka in tests or point to a local dev broker. Integration testing can be done using Docker or services like Redpanda.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 📝 License
|
|
247
|
+
|
|
248
|
+
MIT
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Consumer, ConsumerConfig, Kafka, KafkaConfig, Producer } from 'kafkajs';
|
|
1
|
+
import { Admin, AdminConfig, Consumer, ConsumerConfig, ITopicConfig, Kafka, KafkaConfig, Producer, ProducerConfig } from 'kafkajs';
|
|
2
2
|
import { ILogger, IMessaging, IMessagingSender } from '@kaapi/kaapi';
|
|
3
3
|
export interface KafkaMessagingSender extends IMessagingSender {
|
|
4
4
|
offset?: string;
|
|
@@ -7,24 +7,76 @@ export interface KafkaMessagingConfig extends KafkaConfig {
|
|
|
7
7
|
logger?: ILogger;
|
|
8
8
|
address?: string;
|
|
9
9
|
name?: string;
|
|
10
|
+
producer?: ProducerConfig;
|
|
10
11
|
}
|
|
11
12
|
export interface KafkaMessagingSubscribeConfig extends Partial<ConsumerConfig> {
|
|
12
13
|
fromBeginning?: boolean;
|
|
14
|
+
onReady?(consumer: Consumer): void;
|
|
13
15
|
}
|
|
14
16
|
export declare class KafkaMessaging implements IMessaging {
|
|
15
17
|
#private;
|
|
16
18
|
protected kafka?: Kafka;
|
|
17
19
|
protected logger?: ILogger;
|
|
18
20
|
protected producer?: Producer;
|
|
21
|
+
protected currentProducerId?: string;
|
|
22
|
+
get activeConsumers(): ReadonlySet<Consumer>;
|
|
23
|
+
get activeProducers(): ReadonlySet<Producer>;
|
|
19
24
|
constructor(arg: KafkaMessagingConfig);
|
|
20
25
|
private _createInstance;
|
|
21
|
-
protected
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
protected getKafka(): Kafka | undefined;
|
|
27
|
+
createAdmin(config?: AdminConfig): Promise<Admin | undefined>;
|
|
28
|
+
createTopic(topic: ITopicConfig, config?: {
|
|
29
|
+
validateOnly?: boolean;
|
|
30
|
+
waitForLeaders?: boolean;
|
|
31
|
+
timeout?: number;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Waits for a Kafka topic to become ready (i.e., it exists and has partitions).
|
|
35
|
+
*
|
|
36
|
+
* @param {string} topic - The name of the Kafka topic to check.
|
|
37
|
+
* @param {number} [timeoutMs=10000] - Maximum time (in milliseconds) to wait for the topic to be ready.
|
|
38
|
+
* @param {number} [checkIntervalMs=200] - Interval (in milliseconds) between readiness checks. Must be ≥ 200ms.
|
|
39
|
+
*
|
|
40
|
+
* @throws {Error} If `checkIntervalMs` is less than 200ms.
|
|
41
|
+
* @throws {Error} If `timeoutMs` is less than or equal to `checkIntervalMs`.
|
|
42
|
+
* @throws {Error} If the admin client cannot be created.
|
|
43
|
+
* @throws {Error} If the topic is not ready within the given timeout.
|
|
44
|
+
*
|
|
45
|
+
* @returns {Promise<void>} Resolves when the topic is ready.
|
|
46
|
+
*/
|
|
47
|
+
waitForTopicReady(topic: string, timeoutMs?: number, checkIntervalMs?: number): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Create a new consumer with optional configuration overrides
|
|
50
|
+
* @param groupId Consumer group id
|
|
51
|
+
* @param config Consumer configuration overrides
|
|
52
|
+
* @returns
|
|
53
|
+
*/
|
|
54
|
+
createConsumer(groupId: string, config?: Partial<ConsumerConfig>): Promise<Consumer | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* Create a new producer with optional configuration overrides
|
|
57
|
+
* @param config Producer configuration overrides
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
createProducer(config?: Partial<ProducerConfig>): Promise<Producer | undefined>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the producer
|
|
63
|
+
*/
|
|
24
64
|
getProducer(): Promise<Producer | undefined>;
|
|
65
|
+
/**
|
|
66
|
+
* Disconnect the producer
|
|
67
|
+
*/
|
|
68
|
+
disconnectProducer(): Promise<void>;
|
|
25
69
|
publish<T = unknown>(topic: string, message: T): Promise<void>;
|
|
26
70
|
/**
|
|
27
71
|
* Listen to a topic
|
|
28
72
|
*/
|
|
29
|
-
subscribe<T = unknown>(topic: string, handler: (message: T, sender: KafkaMessagingSender) => Promise<void> | void,
|
|
73
|
+
subscribe<T = unknown>(topic: string, handler: (message: T, sender: KafkaMessagingSender) => Promise<void> | void, config?: KafkaMessagingSubscribeConfig): Promise<void>;
|
|
74
|
+
safeDisconnect(client: Producer | Consumer | Admin, timeoutMs?: number): Promise<unknown>;
|
|
75
|
+
shutdown(): Promise<{
|
|
76
|
+
successProducers: number;
|
|
77
|
+
successConsumers: number;
|
|
78
|
+
successAdmins: number;
|
|
79
|
+
errorCount: number;
|
|
80
|
+
}>;
|
|
30
81
|
}
|
|
82
|
+
export declare function safeDisconnect(client: Producer | Consumer | Admin, timeoutMs?: number): Promise<unknown>;
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _KafkaMessaging_config, _KafkaMessaging_address, _KafkaMessaging_name;
|
|
2
|
+
var _KafkaMessaging_config, _KafkaMessaging_producerConfig, _KafkaMessaging_address, _KafkaMessaging_name, _KafkaMessaging_consumers, _KafkaMessaging_producers, _KafkaMessaging_admins;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.KafkaMessaging = void 0;
|
|
5
|
+
exports.safeDisconnect = safeDisconnect;
|
|
5
6
|
const tslib_1 = require("tslib");
|
|
6
7
|
const kafkajs_1 = require("kafkajs");
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
7
9
|
class KafkaMessaging {
|
|
10
|
+
get activeConsumers() {
|
|
11
|
+
return tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_consumers, "f");
|
|
12
|
+
}
|
|
13
|
+
get activeProducers() {
|
|
14
|
+
return tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_producers, "f");
|
|
15
|
+
}
|
|
8
16
|
constructor(arg) {
|
|
9
17
|
_KafkaMessaging_config.set(this, void 0);
|
|
18
|
+
_KafkaMessaging_producerConfig.set(this, void 0);
|
|
10
19
|
_KafkaMessaging_address.set(this, void 0);
|
|
11
20
|
_KafkaMessaging_name.set(this, void 0);
|
|
12
|
-
|
|
21
|
+
_KafkaMessaging_consumers.set(this, new Set());
|
|
22
|
+
_KafkaMessaging_producers.set(this, new Set());
|
|
23
|
+
_KafkaMessaging_admins.set(this, new Set());
|
|
24
|
+
const { logger, address, name, producer } = arg, kafkaConfig = tslib_1.__rest(arg, ["logger", "address", "name", "producer"]);
|
|
13
25
|
tslib_1.__classPrivateFieldSet(this, _KafkaMessaging_config, kafkaConfig, "f");
|
|
26
|
+
tslib_1.__classPrivateFieldSet(this, _KafkaMessaging_producerConfig, producer, "f");
|
|
14
27
|
tslib_1.__classPrivateFieldSet(this, _KafkaMessaging_name, name, "f");
|
|
15
28
|
tslib_1.__classPrivateFieldSet(this, _KafkaMessaging_address, address, "f");
|
|
16
29
|
this.logger = logger;
|
|
@@ -44,26 +57,83 @@ class KafkaMessaging {
|
|
|
44
57
|
}
|
|
45
58
|
} }, tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_config, "f")));
|
|
46
59
|
}
|
|
47
|
-
|
|
60
|
+
getKafka() {
|
|
61
|
+
if (!this.kafka) {
|
|
62
|
+
this.kafka = this._createInstance();
|
|
63
|
+
}
|
|
64
|
+
return this.kafka;
|
|
65
|
+
}
|
|
66
|
+
createAdmin(config) {
|
|
48
67
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
49
68
|
// Get kafka instance
|
|
50
69
|
const kafka = this.getKafka();
|
|
51
70
|
// If we don't have a connection, abort
|
|
52
71
|
if (!kafka)
|
|
53
72
|
return;
|
|
54
|
-
const admin = kafka.admin();
|
|
73
|
+
const admin = kafka.admin(config);
|
|
55
74
|
yield admin.connect();
|
|
75
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_admins, "f").add(admin);
|
|
76
|
+
admin.on(admin.events.DISCONNECT, () => {
|
|
77
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_admins, "f").delete(admin);
|
|
78
|
+
});
|
|
56
79
|
return admin;
|
|
57
80
|
});
|
|
58
81
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
createTopic(topic, config) {
|
|
83
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const admin = yield this.createAdmin();
|
|
85
|
+
if (!admin)
|
|
86
|
+
throw new Error('Admin client unavailable');
|
|
87
|
+
yield admin.createTopics(Object.assign({ topics: [topic] }, (config || {})));
|
|
88
|
+
yield admin.disconnect();
|
|
89
|
+
});
|
|
64
90
|
}
|
|
65
|
-
|
|
66
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Waits for a Kafka topic to become ready (i.e., it exists and has partitions).
|
|
93
|
+
*
|
|
94
|
+
* @param {string} topic - The name of the Kafka topic to check.
|
|
95
|
+
* @param {number} [timeoutMs=10000] - Maximum time (in milliseconds) to wait for the topic to be ready.
|
|
96
|
+
* @param {number} [checkIntervalMs=200] - Interval (in milliseconds) between readiness checks. Must be ≥ 200ms.
|
|
97
|
+
*
|
|
98
|
+
* @throws {Error} If `checkIntervalMs` is less than 200ms.
|
|
99
|
+
* @throws {Error} If `timeoutMs` is less than or equal to `checkIntervalMs`.
|
|
100
|
+
* @throws {Error} If the admin client cannot be created.
|
|
101
|
+
* @throws {Error} If the topic is not ready within the given timeout.
|
|
102
|
+
*
|
|
103
|
+
* @returns {Promise<void>} Resolves when the topic is ready.
|
|
104
|
+
*/
|
|
105
|
+
waitForTopicReady(topic_1) {
|
|
106
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (topic, timeoutMs = 10000, checkIntervalMs = 200) {
|
|
107
|
+
if (checkIntervalMs < 200) {
|
|
108
|
+
throw new Error(`Invalid checkIntervalMs: ${checkIntervalMs}. It must be at least 200ms to avoid overwhelming the broker.`);
|
|
109
|
+
}
|
|
110
|
+
if (timeoutMs <= checkIntervalMs) {
|
|
111
|
+
throw new Error(`Invalid configuration: timeoutMs (${timeoutMs}) must be greater than checkIntervalMs (${checkIntervalMs}).`);
|
|
112
|
+
}
|
|
113
|
+
const start = Date.now();
|
|
114
|
+
const admin = yield this.createAdmin();
|
|
115
|
+
if (!admin)
|
|
116
|
+
throw new Error('Admin client unavailable');
|
|
117
|
+
while (Date.now() - start < timeoutMs) {
|
|
118
|
+
const metadata = yield admin.fetchTopicMetadata({ topics: [topic] });
|
|
119
|
+
const topicMeta = metadata.topics.find(t => t.name === topic);
|
|
120
|
+
if (topicMeta && topicMeta.partitions.length > 0) {
|
|
121
|
+
yield admin.disconnect();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
yield new Promise(res => setTimeout(res, checkIntervalMs)); // wait 200ms before retry
|
|
125
|
+
}
|
|
126
|
+
yield admin.disconnect();
|
|
127
|
+
throw new Error(`Timeout: Topic "${topic}" did not become ready within ${timeoutMs}ms.`);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a new consumer with optional configuration overrides
|
|
132
|
+
* @param groupId Consumer group id
|
|
133
|
+
* @param config Consumer configuration overrides
|
|
134
|
+
* @returns
|
|
135
|
+
*/
|
|
136
|
+
createConsumer(groupId, config) {
|
|
67
137
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
68
138
|
// Get kafka instance
|
|
69
139
|
const kafka = this.getKafka();
|
|
@@ -71,7 +141,7 @@ class KafkaMessaging {
|
|
|
71
141
|
if (!kafka)
|
|
72
142
|
return;
|
|
73
143
|
let overridenConfig = {
|
|
74
|
-
groupId: `${
|
|
144
|
+
groupId: `${groupId}`,
|
|
75
145
|
readUncommitted: true
|
|
76
146
|
};
|
|
77
147
|
if (config && typeof config == 'object') {
|
|
@@ -79,27 +149,86 @@ class KafkaMessaging {
|
|
|
79
149
|
}
|
|
80
150
|
const consumer = kafka.consumer(overridenConfig);
|
|
81
151
|
yield consumer.connect();
|
|
152
|
+
// track consumers to disconnect them later
|
|
153
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_consumers, "f").add(consumer);
|
|
154
|
+
consumer.on(consumer.events.DISCONNECT, () => {
|
|
155
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_consumers, "f").delete(consumer);
|
|
156
|
+
});
|
|
82
157
|
return consumer;
|
|
83
158
|
});
|
|
84
159
|
}
|
|
85
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Create a new producer with optional configuration overrides
|
|
162
|
+
* @param config Producer configuration overrides
|
|
163
|
+
* @returns
|
|
164
|
+
*/
|
|
165
|
+
createProducer(config) {
|
|
166
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
// Get kafka instance
|
|
168
|
+
const kafka = this.getKafka();
|
|
169
|
+
// If we don't have an instance, abort
|
|
170
|
+
if (!kafka)
|
|
171
|
+
return;
|
|
172
|
+
let overridenConfig = {
|
|
173
|
+
/*
|
|
174
|
+
idempotent: true,
|
|
175
|
+
retry: {
|
|
176
|
+
retries: 5,
|
|
177
|
+
initialRetryTime: 300,
|
|
178
|
+
}
|
|
179
|
+
*/
|
|
180
|
+
};
|
|
181
|
+
if (config && typeof config == 'object') {
|
|
182
|
+
overridenConfig = Object.assign(Object.assign({}, overridenConfig), config);
|
|
183
|
+
}
|
|
184
|
+
const producer = kafka.producer(overridenConfig);
|
|
185
|
+
yield producer.connect();
|
|
186
|
+
// track producers to disconnect them later
|
|
187
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_producers, "f").add(producer);
|
|
188
|
+
producer.on(producer.events.DISCONNECT, () => {
|
|
189
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_producers, "f").delete(producer);
|
|
190
|
+
});
|
|
191
|
+
return producer;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get the producer
|
|
196
|
+
*/
|
|
86
197
|
getProducer() {
|
|
87
198
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
88
199
|
var _a;
|
|
89
200
|
if (!this.producer) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// If we don't have an instance, abort
|
|
93
|
-
if (!kafka)
|
|
201
|
+
const producer = yield this.createProducer(tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_producerConfig, "f"));
|
|
202
|
+
if (!producer)
|
|
94
203
|
return;
|
|
95
|
-
const
|
|
96
|
-
yield producer.connect();
|
|
204
|
+
const producerId = (0, crypto_1.randomBytes)(16).toString('hex');
|
|
97
205
|
this.producer = producer;
|
|
206
|
+
this.currentProducerId = producerId;
|
|
98
207
|
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('✔️ Producer connected');
|
|
208
|
+
producer.on(producer.events.DISCONNECT, () => {
|
|
209
|
+
var _a;
|
|
210
|
+
if (this.currentProducerId === producerId) {
|
|
211
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn('⚠️ Producer disconnected');
|
|
212
|
+
this.producer = undefined;
|
|
213
|
+
this.currentProducerId = undefined;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
99
216
|
}
|
|
100
217
|
return this.producer;
|
|
101
218
|
});
|
|
102
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Disconnect the producer
|
|
222
|
+
*/
|
|
223
|
+
disconnectProducer() {
|
|
224
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
225
|
+
if (this.producer) {
|
|
226
|
+
yield this.producer.disconnect();
|
|
227
|
+
this.producer = undefined;
|
|
228
|
+
this.currentProducerId = undefined;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
103
232
|
publish(topic, message) {
|
|
104
233
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
105
234
|
var _a, _b;
|
|
@@ -130,19 +259,21 @@ class KafkaMessaging {
|
|
|
130
259
|
/**
|
|
131
260
|
* Listen to a topic
|
|
132
261
|
*/
|
|
133
|
-
subscribe(topic, handler,
|
|
262
|
+
subscribe(topic, handler, config) {
|
|
134
263
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
135
264
|
var _a, _b, _c;
|
|
136
265
|
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`👂 Subscribing KAFKA topic "${topic}"`);
|
|
137
266
|
let consumerConfig;
|
|
138
267
|
let fromBeginning;
|
|
139
|
-
|
|
140
|
-
|
|
268
|
+
let onReady;
|
|
269
|
+
if (config) {
|
|
270
|
+
const { fromBeginning: tmpFromBeginning, onReady: tmpOnReady } = config, tmpConsumerConfig = tslib_1.__rest(config, ["fromBeginning", "onReady"]);
|
|
141
271
|
fromBeginning = tmpFromBeginning;
|
|
272
|
+
onReady = tmpOnReady;
|
|
142
273
|
consumerConfig = tmpConsumerConfig;
|
|
143
274
|
}
|
|
144
275
|
// Get kafka consumer
|
|
145
|
-
const consumer = yield this.
|
|
276
|
+
const consumer = yield this.createConsumer(`${tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_name, "f") || 'group'}---${topic}`, consumerConfig);
|
|
146
277
|
// If we don't have a consumer, abort
|
|
147
278
|
if (!consumer)
|
|
148
279
|
return (_b = this.logger) === null || _b === void 0 ? void 0 : _b.error('❌ Could not get consumer');
|
|
@@ -151,7 +282,7 @@ class KafkaMessaging {
|
|
|
151
282
|
topic,
|
|
152
283
|
fromBeginning
|
|
153
284
|
});
|
|
154
|
-
const admin = yield this.
|
|
285
|
+
const admin = yield this.createAdmin();
|
|
155
286
|
if (admin) {
|
|
156
287
|
try {
|
|
157
288
|
const partitions = yield admin.fetchTopicOffsets(topic);
|
|
@@ -202,9 +333,73 @@ class KafkaMessaging {
|
|
|
202
333
|
}
|
|
203
334
|
}),
|
|
204
335
|
});
|
|
336
|
+
onReady === null || onReady === void 0 ? void 0 : onReady(consumer);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
safeDisconnect(client_1) {
|
|
340
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (client, timeoutMs = 5000) {
|
|
341
|
+
return safeDisconnect(client, timeoutMs);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
shutdown() {
|
|
345
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
346
|
+
var _a, _b, _c, _d, _e, _f;
|
|
347
|
+
let errorCount = 0;
|
|
348
|
+
let successProducers = 0;
|
|
349
|
+
let successConsumers = 0;
|
|
350
|
+
let successAdmins = 0;
|
|
351
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info('🛑 Shutting down KafkaMessaging...');
|
|
352
|
+
for (const producer of tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_producers, "f")) {
|
|
353
|
+
try {
|
|
354
|
+
yield this.safeDisconnect(producer);
|
|
355
|
+
successProducers++;
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error('Error disconnecting producer:', e);
|
|
359
|
+
errorCount++;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const consumer of tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_consumers, "f")) {
|
|
363
|
+
try {
|
|
364
|
+
yield consumer.stop(); // Gracefully stop consuming
|
|
365
|
+
yield this.safeDisconnect(consumer);
|
|
366
|
+
successConsumers++;
|
|
367
|
+
}
|
|
368
|
+
catch (e) {
|
|
369
|
+
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error('Error disconnecting consumer:', e);
|
|
370
|
+
errorCount++;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
for (const admin of tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_admins, "f")) {
|
|
374
|
+
try {
|
|
375
|
+
yield this.safeDisconnect(admin);
|
|
376
|
+
tslib_1.__classPrivateFieldGet(this, _KafkaMessaging_admins, "f").delete(admin);
|
|
377
|
+
successAdmins++;
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.error('Error disconnecting admin:', e);
|
|
381
|
+
errorCount++;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
(_e = this.logger) === null || _e === void 0 ? void 0 : _e.info('KafkaMessaging shutdown complete');
|
|
385
|
+
(_f = this.logger) === null || _f === void 0 ? void 0 : _f.info(`Disconnected ${successProducers} producers, ${successConsumers} consumers and ${successAdmins} admins with ${errorCount} errors.`);
|
|
386
|
+
return {
|
|
387
|
+
successProducers,
|
|
388
|
+
successConsumers,
|
|
389
|
+
successAdmins,
|
|
390
|
+
errorCount,
|
|
391
|
+
};
|
|
205
392
|
});
|
|
206
393
|
}
|
|
207
394
|
}
|
|
208
395
|
exports.KafkaMessaging = KafkaMessaging;
|
|
209
|
-
_KafkaMessaging_config = new WeakMap(), _KafkaMessaging_address = new WeakMap(), _KafkaMessaging_name = new WeakMap();
|
|
396
|
+
_KafkaMessaging_config = new WeakMap(), _KafkaMessaging_producerConfig = new WeakMap(), _KafkaMessaging_address = new WeakMap(), _KafkaMessaging_name = new WeakMap(), _KafkaMessaging_consumers = new WeakMap(), _KafkaMessaging_producers = new WeakMap(), _KafkaMessaging_admins = new WeakMap();
|
|
397
|
+
function safeDisconnect(client_1) {
|
|
398
|
+
return tslib_1.__awaiter(this, arguments, void 0, function* (client, timeoutMs = 5000) {
|
|
399
|
+
return Promise.race([
|
|
400
|
+
client.disconnect(),
|
|
401
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Disconnect timed out')), timeoutMs)),
|
|
402
|
+
]);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
210
405
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaapi/kafka-messaging",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Kafka-based messaging for kaapi",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"kafkajs": "^2.2.4",
|
|
16
16
|
"tslib": "^2.8.1",
|
|
17
|
-
"@kaapi/kaapi": "^0.0.
|
|
17
|
+
"@kaapi/kaapi": "^0.0.15"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/mocha": "^10.0.10"
|
|
18
21
|
},
|
|
19
22
|
"scripts": {
|
|
20
23
|
"lint": "eslint .",
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
2
|
+
|
|
3
|
+
// test/kafka-messaging.spec.ts
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import { KafkaMessaging } from '../src/index';
|
|
7
|
+
|
|
8
|
+
describe('KafkaMessaging', () => {
|
|
9
|
+
const kafkaConfig = {
|
|
10
|
+
clientId: 'test-client',
|
|
11
|
+
brokers: process.env.KAFKA_BROKERS ? process.env.KAFKA_BROKERS.split(',') : ['localhost:9092'],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let messaging: KafkaMessaging;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
messaging = new KafkaMessaging(kafkaConfig);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should create and track a producer', async () => {
|
|
21
|
+
const producer = await messaging.createProducer();
|
|
22
|
+
expect(producer).to.exist;
|
|
23
|
+
if (producer)
|
|
24
|
+
expect(messaging.activeProducers.has(producer)).to.be.true;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should create and track a consumer', async () => {
|
|
28
|
+
const consumer = await messaging.createConsumer('test-group');
|
|
29
|
+
expect(consumer).to.exist;
|
|
30
|
+
if (consumer)
|
|
31
|
+
expect(messaging.activeConsumers.has(consumer)).to.be.true;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should disconnect producer safely', async () => {
|
|
35
|
+
const producer = await messaging.createProducer();
|
|
36
|
+
expect(producer).to.exist;
|
|
37
|
+
|
|
38
|
+
if (producer) {
|
|
39
|
+
await messaging.safeDisconnect(producer);
|
|
40
|
+
expect(messaging.activeProducers.has(producer)).to.be.false;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should disconnect consumer safely', async () => {
|
|
45
|
+
const consumer = await messaging.createConsumer('test-group');
|
|
46
|
+
expect(consumer).to.exist;
|
|
47
|
+
if (consumer) {
|
|
48
|
+
await consumer.stop();
|
|
49
|
+
await messaging.safeDisconnect(consumer);
|
|
50
|
+
expect(messaging.activeConsumers.has(consumer)).to.be.false;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should shutdown all tracked clients', async () => {
|
|
55
|
+
await messaging.createProducer();
|
|
56
|
+
await messaging.createConsumer('test-group');
|
|
57
|
+
const result = await messaging.shutdown();
|
|
58
|
+
expect(result.successProducers).to.be.greaterThan(0);
|
|
59
|
+
expect(result.successConsumers).to.be.greaterThan(0);
|
|
60
|
+
expect(result.errorCount).to.equal(0);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('KafkaMessaging Integration', function () {
|
|
65
|
+
this.timeout(20000); // Increase timeout for Kafka operations
|
|
66
|
+
|
|
67
|
+
const kafkaConfig = {
|
|
68
|
+
clientId: 'integration-client',
|
|
69
|
+
brokers: process.env.KAFKA_BROKERS ? process.env.KAFKA_BROKERS.split(',') : ['localhost:9092'],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
let messaging: KafkaMessaging;
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
messaging = new KafkaMessaging(kafkaConfig);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
afterEach(async () => {
|
|
79
|
+
await messaging.shutdown();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should publish and consume a message', async () => {
|
|
83
|
+
const topic = 'test-topic-c';
|
|
84
|
+
await messaging.createTopic({
|
|
85
|
+
topic,
|
|
86
|
+
numPartitions: 1,
|
|
87
|
+
replicationFactor: 1
|
|
88
|
+
}, {
|
|
89
|
+
waitForLeaders: true
|
|
90
|
+
});
|
|
91
|
+
await messaging.waitForTopicReady(topic); // 👈 wait for metadata to settle
|
|
92
|
+
|
|
93
|
+
const message = { hello: 'world' };
|
|
94
|
+
|
|
95
|
+
let received: unknown = null;
|
|
96
|
+
|
|
97
|
+
await messaging.subscribe(topic, (msg) => {
|
|
98
|
+
received = msg;
|
|
99
|
+
}, { fromBeginning: true });
|
|
100
|
+
|
|
101
|
+
await messaging.publish(topic, message);
|
|
102
|
+
|
|
103
|
+
// Wait for message to be consumed
|
|
104
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
105
|
+
|
|
106
|
+
expect(received).to.deep.equal(message);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should return correct shutdown summary', async () => {
|
|
110
|
+
const topic = 'shutdown-topic-c';
|
|
111
|
+
await messaging.createTopic({
|
|
112
|
+
topic,
|
|
113
|
+
numPartitions: 1,
|
|
114
|
+
replicationFactor: 1
|
|
115
|
+
}, {
|
|
116
|
+
waitForLeaders: true
|
|
117
|
+
});
|
|
118
|
+
await messaging.waitForTopicReady(topic); // 👈 wait for metadata to settle
|
|
119
|
+
|
|
120
|
+
await messaging.subscribe(topic, () => { }, { fromBeginning: true });
|
|
121
|
+
await messaging.publish(topic, { test: true });
|
|
122
|
+
|
|
123
|
+
const result = await messaging.shutdown();
|
|
124
|
+
|
|
125
|
+
expect(result.successProducers).to.be.greaterThan(0);
|
|
126
|
+
expect(result.successConsumers).to.be.greaterThan(0);
|
|
127
|
+
expect(result.errorCount).to.equal(0);
|
|
128
|
+
});
|
|
129
|
+
});
|