@healthzkit/kafka 0.0.0
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 +138 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +1 -0
- package/dist/kafkajs.d.mts +16 -0
- package/dist/kafkajs.mjs +1 -0
- package/dist/node-rdkafka.d.mts +17 -0
- package/dist/node-rdkafka.mjs +1 -0
- package/dist/shared-BQHQT909.d.mts +12 -0
- package/dist/shared-BiUsKU63.mjs +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @healthzkit/kafka
|
|
2
|
+
|
|
3
|
+
Kafka **healthzkit** `HealthAdapter` helpers for **[`kafkajs`](https://kafka.js.org/)** and **[`node-rdkafka`](https://github.com/Blizzard/node-rdkafka)**. Successful checks return `ok` with `metadata.latencyMs` plus any fields from an optional `metadata` hook; failures return `fail` with the caught error.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @healthzkit/kafka healthzkit
|
|
9
|
+
# plus one of:
|
|
10
|
+
npm install kafkajs
|
|
11
|
+
npm install node-rdkafka
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Both clients are optional peers—install the library you use.
|
|
15
|
+
|
|
16
|
+
`node-rdkafka` is a native addon (requires `librdkafka` at build/runtime). Prefer **`kafkajs`** when you want a pure JavaScript client.
|
|
17
|
+
|
|
18
|
+
## Shared options
|
|
19
|
+
|
|
20
|
+
Both factories accept `BaseKafkaOptions`:
|
|
21
|
+
|
|
22
|
+
| Option | Description |
|
|
23
|
+
| ---------- | ----------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `metadata` | Optional `(client) => Record<string, unknown>` (sync or async) merged into metadata with `latencyMs`. |
|
|
25
|
+
|
|
26
|
+
Pass either client configuration or an existing client/producer/consumer (not both). The shape depends on the adapter (see below).
|
|
27
|
+
|
|
28
|
+
## `kafkajsAdapter` (`kafkajs`)
|
|
29
|
+
|
|
30
|
+
**Peer:** `kafkajs` ≥ 2.
|
|
31
|
+
|
|
32
|
+
Each check creates an admin client, connects, calls `describeCluster()`, and disconnects the admin handle. The underlying `Kafka` instance is reused when you pass `config`.
|
|
33
|
+
|
|
34
|
+
### Config
|
|
35
|
+
|
|
36
|
+
The adapter lazily imports `kafkajs`, constructs `new Kafka(config)` once, and reuses it across checks.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createHealthKit } from "healthzkit";
|
|
40
|
+
import { kafkajsAdapter } from "@healthzkit/kafka";
|
|
41
|
+
|
|
42
|
+
const kit = createHealthKit({
|
|
43
|
+
checks: [
|
|
44
|
+
{
|
|
45
|
+
name: "kafka",
|
|
46
|
+
type: ["readiness"],
|
|
47
|
+
adapter: kafkajsAdapter({
|
|
48
|
+
config: { brokers: [process.env.KAFKA_BROKERS!] },
|
|
49
|
+
}),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`config` is the first argument to the `Kafka` constructor (for example `brokers`, `clientId`, `ssl`, `sasl`).
|
|
56
|
+
|
|
57
|
+
### Existing client
|
|
58
|
+
|
|
59
|
+
Pass **`client`** as an existing `Kafka` instance from your app. The adapter reuses that client across checks.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { Kafka } from "kafkajs";
|
|
63
|
+
import { kafkajsAdapter } from "@healthzkit/kafka";
|
|
64
|
+
|
|
65
|
+
const kafka = new Kafka({ brokers: [process.env.KAFKA_BROKERS!] });
|
|
66
|
+
|
|
67
|
+
const adapter = kafkajsAdapter({
|
|
68
|
+
client: kafka,
|
|
69
|
+
metadata: () => ({ driver: "kafkajs" }),
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## `nodeRdKafkaAdapter` (`node-rdkafka`)
|
|
74
|
+
|
|
75
|
+
**Peer:** `node-rdkafka` ≥ 3.
|
|
76
|
+
|
|
77
|
+
Each check fetches broker metadata via `getMetadata()` when the client is already connected, or `connect({}, cb)` otherwise. That exercises the broker path without producing or consuming messages.
|
|
78
|
+
|
|
79
|
+
### Config
|
|
80
|
+
|
|
81
|
+
The adapter lazily imports `node-rdkafka`, constructs `new Producer(config)` once, and reuses it across checks.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { nodeRdKafkaAdapter } from "@healthzkit/kafka";
|
|
85
|
+
|
|
86
|
+
const adapter = nodeRdKafkaAdapter({
|
|
87
|
+
config: { "bootstrap.servers": process.env.KAFKA_BROKERS! },
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`config` is a `ProducerGlobalConfig` object (for example `bootstrap.servers`, `security.protocol`, `sasl.username`).
|
|
92
|
+
|
|
93
|
+
### Existing client
|
|
94
|
+
|
|
95
|
+
Pass **`client`** as an existing `Producer` or `KafkaConsumer` from your app. The adapter reuses that instance across checks.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { Producer } from "node-rdkafka";
|
|
99
|
+
import { nodeRdKafkaAdapter } from "@healthzkit/kafka";
|
|
100
|
+
|
|
101
|
+
const producer = new Producer({
|
|
102
|
+
"bootstrap.servers": process.env.KAFKA_BROKERS!,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const adapter = nodeRdKafkaAdapter({
|
|
106
|
+
client: producer,
|
|
107
|
+
metadata: () => ({ driver: "node-rdkafka" }),
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Check result
|
|
112
|
+
|
|
113
|
+
On success:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"status": "ok",
|
|
118
|
+
"metadata": { "latencyMs": 12 }
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
On failure, `status` is `"fail"` and `error` is set (see [healthzkit](https://github.com/alasti-company/healthzkit) for how that rolls up into probe responses).
|
|
123
|
+
|
|
124
|
+
## Scheduling
|
|
125
|
+
|
|
126
|
+
For brokers that should not be probed on every request, pair these adapters with a **`schedule`** on the check so readiness reads cached results instead of hitting Kafka on every probe. See the **Scheduling** section in the `healthzkit` README.
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
|
|
130
|
+
From the monorepo root:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
vp install
|
|
134
|
+
vp test --filter @healthzkit/kafka
|
|
135
|
+
vp pack --filter @healthzkit/kafka
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
See the repo root `AGENTS.md` for Vite+ / `vp` conventions.
|
package/dist/index.d.mts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{kafkajsAdapter as e}from"./kafkajs.mjs";import{nodeRdKafkaAdapter as t}from"./node-rdkafka.mjs";export{e as kafkajsAdapter,t as nodeRdKafkaAdapter};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { n as HealthAdapter, t as BaseKafkaOptions } from "./shared-BQHQT909.mjs";
|
|
2
|
+
import { Kafka } from "kafkajs";
|
|
3
|
+
|
|
4
|
+
//#region src/kafkajs.d.ts
|
|
5
|
+
interface KafkaJsAdapterOptionsWithClient extends BaseKafkaOptions<Kafka> {
|
|
6
|
+
client: Kafka;
|
|
7
|
+
config?: never;
|
|
8
|
+
}
|
|
9
|
+
interface KafkaJsAdapterOptionsWithConfig extends BaseKafkaOptions<Kafka> {
|
|
10
|
+
config: ConstructorParameters<typeof Kafka>[0];
|
|
11
|
+
client?: never;
|
|
12
|
+
}
|
|
13
|
+
type KafkaJsAdapterOptions = KafkaJsAdapterOptionsWithClient | KafkaJsAdapterOptionsWithConfig;
|
|
14
|
+
declare function kafkajsAdapter(options: KafkaJsAdapterOptions): HealthAdapter;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { KafkaJsAdapterOptions, KafkaJsAdapterOptionsWithClient, KafkaJsAdapterOptionsWithConfig, kafkajsAdapter };
|
package/dist/kafkajs.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./shared-BiUsKU63.mjs";function n(n){let r=null;async function i(){if(`client`in n&&n.client)return n.client;if(!r){let{Kafka:e}=await import(`kafkajs`);r=new e(n.config)}return r}return{async check(){let r=null;try{let t=await i(),a=Date.now();r=t.admin(),await r.connect(),await r.describeCluster();let o=Date.now()-a,s=n.metadata?n.metadata(t):void 0;return e(o,s instanceof Promise?await s:s)}catch(e){return t(e)}finally{r&&await r.disconnect().catch(()=>{})}}}}export{n as kafkajsAdapter};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { n as HealthAdapter, t as BaseKafkaOptions } from "./shared-BQHQT909.mjs";
|
|
2
|
+
import { KafkaConsumer, Producer, ProducerGlobalConfig } from "node-rdkafka";
|
|
3
|
+
|
|
4
|
+
//#region src/node-rdkafka.d.ts
|
|
5
|
+
type RdKafkaClient = Producer | KafkaConsumer;
|
|
6
|
+
interface NodeRdKafkaOptionsWithClient extends BaseKafkaOptions<RdKafkaClient> {
|
|
7
|
+
client: RdKafkaClient;
|
|
8
|
+
config?: never;
|
|
9
|
+
}
|
|
10
|
+
interface NodeRdKafkaOptionsWithConfig extends BaseKafkaOptions<RdKafkaClient> {
|
|
11
|
+
config: ProducerGlobalConfig;
|
|
12
|
+
client?: never;
|
|
13
|
+
}
|
|
14
|
+
type NodeRdKafkaAdapterOptions = NodeRdKafkaOptionsWithClient | NodeRdKafkaOptionsWithConfig;
|
|
15
|
+
declare function nodeRdKafkaAdapter(options: NodeRdKafkaAdapterOptions): HealthAdapter;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { NodeRdKafkaAdapterOptions, NodeRdKafkaOptionsWithClient, NodeRdKafkaOptionsWithConfig, nodeRdKafkaAdapter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./shared-BiUsKU63.mjs";function n(e){return new Promise((t,n)=>{let r=e=>{e?n(e):t()};if(e.isConnected()){e.getMetadata({},r);return}e.connect({},t=>{if(t){n(t);return}e.getMetadata({},r)})})}function r(r){let i=null,a=null;async function o(){return`client`in r&&r.client?r.client:i||(a||=(async()=>{try{let{Producer:e}=await import(`node-rdkafka`);return i=new e(r.config),i}finally{a=null}})(),a)}return{async check(){try{let t=await o(),i=Date.now();await n(t);let a=Date.now()-i,s=r.metadata?r.metadata(t):void 0;return e(a,s instanceof Promise?await s:s)}catch(e){return t(e)}}}}export{r as nodeRdKafkaAdapter};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HealthAdapter, MetadataFn } from "@healthzkit/shared";
|
|
2
|
+
|
|
3
|
+
//#region src/shared.d.ts
|
|
4
|
+
interface BaseKafkaOptions<TClient> {
|
|
5
|
+
/**
|
|
6
|
+
* Optional function to populate metadata in the check result.
|
|
7
|
+
* Receives the resolved client so you can additional operations.
|
|
8
|
+
*/
|
|
9
|
+
metadata?: MetadataFn<TClient>;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { HealthAdapter as n, BaseKafkaOptions as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{buildErrorResult as e,buildResult as t}from"@healthzkit/shared";export{t as n,e as t};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@healthzkit/kafka",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/alasti-company/healthzkit.dev",
|
|
8
|
+
"directory": "packages/kafka"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./dist/index.mjs",
|
|
16
|
+
"./kafkajs": "./dist/kafkajs.mjs",
|
|
17
|
+
"./node-rdkafka": "./dist/node-rdkafka.mjs",
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "vp pack",
|
|
25
|
+
"dev": "vp pack --watch",
|
|
26
|
+
"test": "vp test",
|
|
27
|
+
"check": "vp check",
|
|
28
|
+
"prepublishOnly": "vp run build"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@healthzkit/shared": "workspace:*"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "catalog:",
|
|
35
|
+
"@typescript/native-preview": "7.0.0-dev.20260509.2",
|
|
36
|
+
"bumpp": "^11.1.0",
|
|
37
|
+
"healthzkit": "workspace:*",
|
|
38
|
+
"kafkajs": "^2.2.4",
|
|
39
|
+
"node-rdkafka": "^3.6.1",
|
|
40
|
+
"typescript": "catalog:",
|
|
41
|
+
"vite-plus": "catalog:"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"kafkajs": ">=2.0.0",
|
|
45
|
+
"node-rdkafka": ">=3.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"kafkajs": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"node-rdkafka": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|