sentinel-kafka-manager 1.0.1 → 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/README.md +349 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,350 @@ npm run build
|
|
|
48
48
|
- Kafka cluster reachable from the service
|
|
49
49
|
- `kafkajs` is included automatically as a dependency of this package
|
|
50
50
|
|
|
51
|
+
## Full Service Example
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { KafkaManager } from 'sentinel-kafka-manager'
|
|
55
|
+
|
|
56
|
+
const kafkaManager = KafkaManager.fromEnv({
|
|
57
|
+
clientId: 'claims-api',
|
|
58
|
+
mode: 'external',
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
async function bootstrap(): Promise<void> {
|
|
62
|
+
await kafkaManager.provisionTopics([
|
|
63
|
+
{
|
|
64
|
+
topic: 'claims.created',
|
|
65
|
+
numPartitions: 6,
|
|
66
|
+
replicationFactor: 3,
|
|
67
|
+
},
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
await kafkaManager.publish({
|
|
71
|
+
topic: 'claims.created',
|
|
72
|
+
key: 'claim-1001',
|
|
73
|
+
payload: {
|
|
74
|
+
claimId: 'claim-1001',
|
|
75
|
+
source: 'claims-api',
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
await kafkaManager.runConsumer({
|
|
80
|
+
groupId: 'claims-api-group',
|
|
81
|
+
topic: 'claims.created',
|
|
82
|
+
dlqTopic: 'claims.created.dlq',
|
|
83
|
+
onMessage: async ({ message, headers }) => {
|
|
84
|
+
console.log('Received event:', {
|
|
85
|
+
traceId: headers['x-trace-id'],
|
|
86
|
+
payload: message,
|
|
87
|
+
})
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
bootstrap().catch(async (error) => {
|
|
93
|
+
console.error('Kafka bootstrap failed:', error)
|
|
94
|
+
await kafkaManager.disconnect()
|
|
95
|
+
process.exit(1)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
process.on('SIGINT', async () => {
|
|
99
|
+
await kafkaManager.disconnect()
|
|
100
|
+
process.exit(0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
process.on('SIGTERM', async () => {
|
|
104
|
+
await kafkaManager.disconnect()
|
|
105
|
+
process.exit(0)
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Create A Kafka Server With This Repo
|
|
110
|
+
|
|
111
|
+
This repository already includes a full local Kafka server setup in [docker-compose.yml](/var/www/html/matrix-project/sentinel-kafka-manager/docker-compose.yml) and sample environment values in [.env.local.example](/var/www/html/matrix-project/sentinel-kafka-manager/.env.local.example).
|
|
112
|
+
|
|
113
|
+
The stack includes:
|
|
114
|
+
|
|
115
|
+
- 3 KRaft controllers
|
|
116
|
+
- 3 Kafka brokers
|
|
117
|
+
- 1 Kafka UI instance
|
|
118
|
+
|
|
119
|
+
### 1. Create your `.env`
|
|
120
|
+
|
|
121
|
+
Copy the example file:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
cp .env.local.example .env
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If you want a standard localhost setup, the example values are already suitable.
|
|
128
|
+
|
|
129
|
+
### 2. Start the Kafka cluster
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
docker compose --env-file .env up -d
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This creates:
|
|
136
|
+
|
|
137
|
+
- controller quorum on port `9093` inside Docker
|
|
138
|
+
- internal broker traffic on port `9092` inside Docker
|
|
139
|
+
- host-accessible broker ports `29092`, `39092`, and `49092`
|
|
140
|
+
- Kafka UI on `127.0.0.1:5001`
|
|
141
|
+
|
|
142
|
+
### 3. Stop the Kafka cluster
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
docker compose --env-file .env down
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
To also remove persisted Kafka data volumes:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
docker compose --env-file .env down -v
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 4. Check container status
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
docker compose --env-file .env ps
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 5. Current broker endpoints
|
|
161
|
+
|
|
162
|
+
For applications running on your host machine:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
localhost:29092
|
|
166
|
+
localhost:39092
|
|
167
|
+
localhost:49092
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
For applications running inside Docker on the same Compose network:
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
broker-1:9092
|
|
174
|
+
broker-2:9092
|
|
175
|
+
broker-3:9092
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Important:
|
|
179
|
+
|
|
180
|
+
- application clients must connect to brokers, not controllers
|
|
181
|
+
- controllers are internal cluster metadata nodes only
|
|
182
|
+
- `mode: 'external'` is for host-based apps
|
|
183
|
+
- `mode: 'internal'` is for Dockerized apps on the same network
|
|
184
|
+
|
|
185
|
+
## Kafka UI Usage
|
|
186
|
+
|
|
187
|
+
The Docker stack also starts Kafka UI for cluster inspection.
|
|
188
|
+
|
|
189
|
+
### Open the UI
|
|
190
|
+
|
|
191
|
+
Visit:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
http://127.0.0.1:5001
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Login credentials
|
|
198
|
+
|
|
199
|
+
By default, the UI uses the credentials from `.env`:
|
|
200
|
+
|
|
201
|
+
```env
|
|
202
|
+
KAFKA_UI_USERNAME=admin
|
|
203
|
+
KAFKA_UI_PASSWORD=Admin@007
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### What the UI connects to
|
|
207
|
+
|
|
208
|
+
Kafka UI is preconfigured in `docker-compose.yml` to use all three brokers:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
broker-1:9092,broker-2:9092,broker-3:9092
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The cluster name shown in the UI comes from:
|
|
215
|
+
|
|
216
|
+
```env
|
|
217
|
+
KAFKA_UI_CLUSTER_NAME=Project Omni Enterprise Kafka
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### What you can do in the UI
|
|
221
|
+
|
|
222
|
+
- view brokers and cluster health
|
|
223
|
+
- inspect topics and partitions
|
|
224
|
+
- browse messages
|
|
225
|
+
- inspect consumer groups
|
|
226
|
+
- check offsets and lag
|
|
227
|
+
|
|
228
|
+
### Read-only mode
|
|
229
|
+
|
|
230
|
+
The example `.env` sets:
|
|
231
|
+
|
|
232
|
+
```env
|
|
233
|
+
KAFKA_UI_READONLY=true
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
That means the UI is intended for safe inspection only.
|
|
237
|
+
|
|
238
|
+
If you want to create topics or make changes from the UI, change it to:
|
|
239
|
+
|
|
240
|
+
```env
|
|
241
|
+
KAFKA_UI_READONLY=false
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Then restart the stack:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
docker compose --env-file .env up -d
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Typical UI flow
|
|
251
|
+
|
|
252
|
+
1. Start the Docker stack.
|
|
253
|
+
2. Open `http://127.0.0.1:5001`.
|
|
254
|
+
3. Log in with `KAFKA_UI_USERNAME` and `KAFKA_UI_PASSWORD`.
|
|
255
|
+
4. Open the configured cluster.
|
|
256
|
+
5. Go to Topics, Consumer Groups, or Brokers as needed.
|
|
257
|
+
|
|
258
|
+
## Docker Compose And `.env` Reference
|
|
259
|
+
|
|
260
|
+
This project does not use a separate `Dockerfile` for Kafka. The Kafka server is created from `docker-compose.yml` and environment values from `.env`.
|
|
261
|
+
|
|
262
|
+
### Core Kafka image and cluster identity
|
|
263
|
+
|
|
264
|
+
```env
|
|
265
|
+
KAFKA_IMAGE=confluentinc/cp-kafka:7.6.6
|
|
266
|
+
KAFKA_CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk
|
|
267
|
+
KAFKA_RESTART_POLICY=unless-stopped
|
|
268
|
+
KAFKA_STOP_GRACE_PERIOD=60s
|
|
269
|
+
KAFKA_NETWORK_NAME=kafka-network
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- `KAFKA_IMAGE`: Kafka container image used by controllers and brokers
|
|
273
|
+
- `KAFKA_CLUSTER_ID`: shared KRaft cluster id for all nodes
|
|
274
|
+
- `KAFKA_NETWORK_NAME`: Docker network name used by the full stack
|
|
275
|
+
|
|
276
|
+
### Controller quorum settings
|
|
277
|
+
|
|
278
|
+
```env
|
|
279
|
+
KAFKA_CONTROLLER_PORT=9093
|
|
280
|
+
KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER
|
|
281
|
+
KAFKA_CONTROLLER_QUORUM_VOTERS=1@controller-1:9093,2@controller-2:9093,3@controller-3:9093
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- controllers run only inside Docker
|
|
285
|
+
- apps should never use these controller addresses as Kafka client brokers
|
|
286
|
+
|
|
287
|
+
### Broker listener settings
|
|
288
|
+
|
|
289
|
+
```env
|
|
290
|
+
KAFKA_BROKER_BIND_ADDRESS=0.0.0.0
|
|
291
|
+
KAFKA_EXTERNAL_HOST=localhost
|
|
292
|
+
KAFKA_BROKER_INTERNAL_PORT=9092
|
|
293
|
+
KAFKA_BROKER_EXTERNAL_CONTAINER_PORT=19092
|
|
294
|
+
KAFKA_BROKER_1_EXTERNAL_PORT=29092
|
|
295
|
+
KAFKA_BROKER_2_EXTERNAL_PORT=39092
|
|
296
|
+
KAFKA_BROKER_3_EXTERNAL_PORT=49092
|
|
297
|
+
KAFKA_INTER_BROKER_LISTENER_NAME=INTERNAL
|
|
298
|
+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
- `KAFKA_EXTERNAL_HOST=localhost` exposes brokers to your host machine
|
|
302
|
+
- `KAFKA_BROKER_1_EXTERNAL_PORT`, `KAFKA_BROKER_2_EXTERNAL_PORT`, and `KAFKA_BROKER_3_EXTERNAL_PORT` are the ports your local apps should use
|
|
303
|
+
- `KAFKA_BROKER_INTERNAL_PORT=9092` is used by containers on the Docker network
|
|
304
|
+
|
|
305
|
+
### Replication and durability defaults
|
|
306
|
+
|
|
307
|
+
```env
|
|
308
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=3
|
|
309
|
+
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=3
|
|
310
|
+
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=2
|
|
311
|
+
KAFKA_DEFAULT_REPLICATION_FACTOR=3
|
|
312
|
+
KAFKA_MIN_INSYNC_REPLICAS=2
|
|
313
|
+
KAFKA_NUM_PARTITIONS=6
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
These values are designed for the included three-broker cluster.
|
|
317
|
+
|
|
318
|
+
### Broker behavior
|
|
319
|
+
|
|
320
|
+
```env
|
|
321
|
+
KAFKA_AUTO_CREATE_TOPICS_ENABLE=false
|
|
322
|
+
KAFKA_DELETE_TOPIC_ENABLE=true
|
|
323
|
+
KAFKA_LOG_RETENTION_HOURS=168
|
|
324
|
+
KAFKA_LOG_SEGMENT_BYTES=1073741824
|
|
325
|
+
KAFKA_MESSAGE_MAX_BYTES=10485880
|
|
326
|
+
KAFKA_REPLICA_FETCH_MAX_BYTES=10485880
|
|
327
|
+
KAFKA_SOCKET_REQUEST_MAX_BYTES=104857600
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
- topics are not auto-created by default
|
|
331
|
+
- deleting topics is allowed
|
|
332
|
+
- retention is 7 days by default
|
|
333
|
+
|
|
334
|
+
### Storage and safety limits
|
|
335
|
+
|
|
336
|
+
```env
|
|
337
|
+
KAFKA_LOG_DIRS=/var/lib/kafka/data
|
|
338
|
+
KAFKA_ULIMIT_NOFILE_SOFT=65536
|
|
339
|
+
KAFKA_ULIMIT_NOFILE_HARD=65536
|
|
340
|
+
KAFKA_LOG_MAX_SIZE=100m
|
|
341
|
+
KAFKA_LOG_MAX_FILE=5
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Kafka UI settings
|
|
345
|
+
|
|
346
|
+
```env
|
|
347
|
+
KAFKA_UI_IMAGE=provectuslabs/kafka-ui:latest
|
|
348
|
+
KAFKA_UI_CONTAINER_NAME=kafka-ui
|
|
349
|
+
KAFKA_UI_HOSTNAME=kafka-ui
|
|
350
|
+
KAFKA_UI_RESTART_POLICY=unless-stopped
|
|
351
|
+
KAFKA_UI_BIND_ADDRESS=127.0.0.1
|
|
352
|
+
KAFKA_UI_PORT=5001
|
|
353
|
+
KAFKA_UI_DYNAMIC_CONFIG_ENABLED=false
|
|
354
|
+
KAFKA_UI_CLUSTER_NAME=Project Omni Enterprise Kafka
|
|
355
|
+
KAFKA_UI_READONLY=true
|
|
356
|
+
KAFKA_UI_AUTH_TYPE=LOGIN_FORM
|
|
357
|
+
KAFKA_UI_USERNAME=admin
|
|
358
|
+
KAFKA_UI_PASSWORD=Admin@007
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
- `KAFKA_UI_BIND_ADDRESS=127.0.0.1` keeps the UI local-only
|
|
362
|
+
- `KAFKA_UI_PORT=5001` publishes the UI on your machine
|
|
363
|
+
- `KAFKA_UI_READONLY=true` prevents write actions from the UI
|
|
364
|
+
|
|
365
|
+
### Healthcheck settings
|
|
366
|
+
|
|
367
|
+
```env
|
|
368
|
+
KAFKA_HEALTHCHECK_INTERVAL=10s
|
|
369
|
+
KAFKA_HEALTHCHECK_TIMEOUT=5s
|
|
370
|
+
KAFKA_HEALTHCHECK_RETRIES=15
|
|
371
|
+
KAFKA_HEALTHCHECK_START_PERIOD=30s
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Creating Topics
|
|
375
|
+
|
|
376
|
+
Because `KAFKA_AUTO_CREATE_TOPICS_ENABLE=false`, topics should be created deliberately.
|
|
377
|
+
|
|
378
|
+
You have two good options:
|
|
379
|
+
|
|
380
|
+
- create topics from your service with `kafkaManager.provisionTopics()`
|
|
381
|
+
- allow UI-based creation by setting `KAFKA_UI_READONLY=false`
|
|
382
|
+
|
|
383
|
+
Example with this package:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
await kafkaManager.provisionTopics([
|
|
387
|
+
{
|
|
388
|
+
topic: 'claims.created',
|
|
389
|
+
numPartitions: 6,
|
|
390
|
+
replicationFactor: 3,
|
|
391
|
+
},
|
|
392
|
+
])
|
|
393
|
+
```
|
|
394
|
+
|
|
51
395
|
## Enterprise Features
|
|
52
396
|
|
|
53
397
|
This version now includes a stronger production baseline:
|
|
@@ -544,64 +888,6 @@ const kafkaManager = KafkaManager.fromEnv({
|
|
|
544
888
|
|
|
545
889
|
This package is designed to work with that exact broker layout.
|
|
546
890
|
|
|
547
|
-
## Full Service Example
|
|
548
|
-
|
|
549
|
-
```ts
|
|
550
|
-
import { KafkaManager } from 'sentinel-kafka-manager'
|
|
551
|
-
|
|
552
|
-
const kafkaManager = KafkaManager.fromEnv({
|
|
553
|
-
clientId: 'claims-api',
|
|
554
|
-
mode: 'external',
|
|
555
|
-
})
|
|
556
|
-
|
|
557
|
-
async function bootstrap(): Promise<void> {
|
|
558
|
-
await kafkaManager.provisionTopics([
|
|
559
|
-
{
|
|
560
|
-
topic: 'claims.created',
|
|
561
|
-
numPartitions: 6,
|
|
562
|
-
replicationFactor: 3,
|
|
563
|
-
},
|
|
564
|
-
])
|
|
565
|
-
|
|
566
|
-
await kafkaManager.publish({
|
|
567
|
-
topic: 'claims.created',
|
|
568
|
-
key: 'claim-1001',
|
|
569
|
-
payload: {
|
|
570
|
-
claimId: 'claim-1001',
|
|
571
|
-
source: 'claims-api',
|
|
572
|
-
},
|
|
573
|
-
})
|
|
574
|
-
|
|
575
|
-
await kafkaManager.runConsumer({
|
|
576
|
-
groupId: 'claims-api-group',
|
|
577
|
-
topic: 'claims.created',
|
|
578
|
-
dlqTopic: 'claims.created.dlq',
|
|
579
|
-
onMessage: async ({ message, headers }) => {
|
|
580
|
-
console.log('Received event:', {
|
|
581
|
-
traceId: headers['x-trace-id'],
|
|
582
|
-
payload: message,
|
|
583
|
-
})
|
|
584
|
-
},
|
|
585
|
-
})
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
bootstrap().catch(async (error) => {
|
|
589
|
-
console.error('Kafka bootstrap failed:', error)
|
|
590
|
-
await kafkaManager.disconnect()
|
|
591
|
-
process.exit(1)
|
|
592
|
-
})
|
|
593
|
-
|
|
594
|
-
process.on('SIGINT', async () => {
|
|
595
|
-
await kafkaManager.disconnect()
|
|
596
|
-
process.exit(0)
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
process.on('SIGTERM', async () => {
|
|
600
|
-
await kafkaManager.disconnect()
|
|
601
|
-
process.exit(0)
|
|
602
|
-
})
|
|
603
|
-
```
|
|
604
|
-
|
|
605
891
|
## API Summary
|
|
606
892
|
|
|
607
893
|
### `new KafkaManager(options)`
|
|
@@ -874,31 +1160,6 @@ For most SaaS services, the cleanest pattern is:
|
|
|
874
1160
|
5. Catch `KafkaManagerError` and branch on `error.code`.
|
|
875
1161
|
6. Wrap service outcomes in `OperationResponse<T>` where useful.
|
|
876
1162
|
|
|
877
|
-
## Publishing This Package
|
|
878
|
-
|
|
879
|
-
Build:
|
|
880
|
-
|
|
881
|
-
```bash
|
|
882
|
-
npm run build
|
|
883
|
-
```
|
|
884
|
-
|
|
885
|
-
Publish:
|
|
886
|
-
|
|
887
|
-
```bash
|
|
888
|
-
npm publish
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
If npm rejects the publish:
|
|
892
|
-
|
|
893
|
-
- `403` usually means authentication, 2FA, or token permission issues
|
|
894
|
-
- `404` usually means the package name is unavailable or not publishable by your account
|
|
895
|
-
|
|
896
|
-
Useful check:
|
|
897
|
-
|
|
898
|
-
```bash
|
|
899
|
-
npm whoami
|
|
900
|
-
```
|
|
901
|
-
|
|
902
1163
|
## Notes
|
|
903
1164
|
|
|
904
1165
|
- Your current Kafka cluster works fine with PLAINTEXT, so SSL and SASL are optional unless your environment changes
|
|
@@ -907,6 +1168,11 @@ npm whoami
|
|
|
907
1168
|
|
|
908
1169
|
## Links
|
|
909
1170
|
|
|
1171
|
+
- npm deployment guide: [NPM_DEPLOYMENT.md](/var/www/html/matrix-project/sentinel-kafka-manager/NPM_DEPLOYMENT.md)
|
|
1172
|
+
- Example folder: [examples/service-module-usage/README.md](/var/www/html/matrix-project/sentinel-kafka-manager/examples/service-module-usage/README.md)
|
|
1173
|
+
- Service module guide: [SERVICE_MODULE_USAGE.md](/var/www/html/matrix-project/sentinel-kafka-manager/SERVICE_MODULE_USAGE.md)
|
|
1174
|
+
- GitHub: https://github.com/dilipshaw2024/sentinel-kafka-manager
|
|
1175
|
+
- npm: https://www.npmjs.com/package/sentinel-kafka-manager
|
|
910
1176
|
- LinkedIn: https://www.linkedin.com/in/dilip-shaw-2740769/
|
|
911
1177
|
|
|
912
1178
|
## About Me
|