@openstatus/health-kafka 0.1.4-dev.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 +75 -0
- package/dist/_virtual/rolldown_runtime.cjs +30 -0
- package/dist/mod.cjs +34 -0
- package/dist/mod.d.cts +29 -0
- package/dist/mod.d.cts.map +1 -0
- package/dist/mod.d.ts +29 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +33 -0
- package/dist/mod.js.map +1 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @openstatus/health-kafka
|
|
2
|
+
|
|
3
|
+
[Apache Kafka](https://kafka.apache.org/) probe for
|
|
4
|
+
[`@openstatus/health`](https://jsr.io/@openstatus/health). Describes the
|
|
5
|
+
cluster through a connected [KafkaJS](https://kafka.js.org/)-style `Admin`
|
|
6
|
+
client — one metadata request to the broker — and fails the check when no
|
|
7
|
+
broker answers or the cluster reports none.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
deno add jsr:@openstatus/health jsr:@openstatus/health-kafka
|
|
11
|
+
npm install @openstatus/health @openstatus/health-kafka
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { Kafka } from "kafkajs";
|
|
16
|
+
import { createHealthHandler } from "@openstatus/health";
|
|
17
|
+
import { kafkaProbe } from "@openstatus/health-kafka";
|
|
18
|
+
|
|
19
|
+
const kafka = new Kafka({ brokers: env.KAFKA_BROKERS.split(",") });
|
|
20
|
+
const admin = kafka.admin();
|
|
21
|
+
await admin.connect();
|
|
22
|
+
|
|
23
|
+
Deno.serve(
|
|
24
|
+
createHealthHandler({ probes: [kafkaProbe({ admin })] }),
|
|
25
|
+
);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Connect the `Admin` client once at start-up and keep it: KafkaJS only
|
|
29
|
+
sends the metadata request over an established connection, and creating
|
|
30
|
+
one per health request would add a broker handshake to every poll.
|
|
31
|
+
`describeCluster()` needs no topic and no ACL beyond `Describe` on the
|
|
32
|
+
cluster, so it works with the most restricted credentials. The
|
|
33
|
+
`@confluentinc/kafka-javascript` KafkaJS-compatible `Admin` does not
|
|
34
|
+
implement `describeCluster()`, so it is not supported.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
kafkaProbe({
|
|
38
|
+
admin,
|
|
39
|
+
// optional overrides from the Probe contract
|
|
40
|
+
name: "events",
|
|
41
|
+
critical: true,
|
|
42
|
+
timeoutMs: 2000,
|
|
43
|
+
skip: () => env.KAFKA_BROKERS == null,
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Non-critical by default: Kafka usually carries events processed out of
|
|
48
|
+
band, so an outage degrades the report instead of taking the service out
|
|
49
|
+
of rotation. Set `critical: true` when requests cannot complete without
|
|
50
|
+
producing.
|
|
51
|
+
|
|
52
|
+
The admin client is typed structurally as
|
|
53
|
+
`{ describeCluster(): PromiseLike<{ brokers: [...] }> }`, so `kafkajs` is an
|
|
54
|
+
optional peer dependency for its types only and the probe adds no runtime
|
|
55
|
+
import of it. The factory throws
|
|
56
|
+
`ProbeConfigError` at construction when the client has no
|
|
57
|
+
`describeCluster()`.
|
|
58
|
+
|
|
59
|
+
## About openstatus
|
|
60
|
+
|
|
61
|
+
[openstatus](https://www.openstatus.dev/) is the open-source uptime monitoring
|
|
62
|
+
and status page platform. This package is part of
|
|
63
|
+
[`@openstatus/health`](https://github.com/openstatusHQ/health), the `/health`
|
|
64
|
+
endpoints behind openstatus's own services, extracted so any JavaScript server
|
|
65
|
+
can expose one. Point an
|
|
66
|
+
[openstatus monitor](https://www.openstatus.dev/docs/reference/http-monitor)
|
|
67
|
+
at the endpoint and assert on `status` in the body to be alerted on
|
|
68
|
+
`degraded` before it becomes `unhealthy`.
|
|
69
|
+
|
|
70
|
+
Source: [github.com/openstatusHQ/health](https://github.com/openstatusHQ/health).
|
|
71
|
+
Issues and PRs welcome.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
[MIT](https://github.com/openstatusHQ/health/blob/main/LICENSE)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
|
|
25
|
+
Object.defineProperty(exports, '__toESM', {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () {
|
|
28
|
+
return __toESM;
|
|
29
|
+
}
|
|
30
|
+
});
|
package/dist/mod.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const __openstatus_health = require_rolldown_runtime.__toESM(require("@openstatus/health"));
|
|
3
|
+
|
|
4
|
+
//#region src/mod.ts
|
|
5
|
+
/** Probe name when `name` is unset. */
|
|
6
|
+
const kafkaDefaultName = "kafka";
|
|
7
|
+
/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
|
|
8
|
+
function kafkaProbe(options) {
|
|
9
|
+
const admin = options.admin;
|
|
10
|
+
if (typeof admin?.describeCluster !== "function") throw new __openstatus_health.ProbeConfigError("kafkaProbe", "admin", `must expose describeCluster(), got ${describe(admin)}`);
|
|
11
|
+
return {
|
|
12
|
+
name: options.name ?? kafkaDefaultName,
|
|
13
|
+
critical: options.critical ?? false,
|
|
14
|
+
timeoutMs: options.timeoutMs,
|
|
15
|
+
skip: options.skip,
|
|
16
|
+
run: async () => {
|
|
17
|
+
const cluster = await admin.describeCluster();
|
|
18
|
+
const brokers = cluster?.brokers;
|
|
19
|
+
if (!Array.isArray(brokers)) throw new Error("unexpected response shape");
|
|
20
|
+
if (brokers.length === 0) throw new Error("no brokers in cluster");
|
|
21
|
+
return { brokers: brokers.length };
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function describe(admin) {
|
|
26
|
+
if (admin == null) return String(admin);
|
|
27
|
+
if (typeof admin !== "object") return typeof admin;
|
|
28
|
+
const keys = Object.keys(admin);
|
|
29
|
+
return keys.length === 0 ? "an object with no keys" : `an object with keys ${keys.slice(0, 8).join(", ")}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
exports.kafkaDefaultName = kafkaDefaultName;
|
|
34
|
+
exports.kafkaProbe = kafkaProbe;
|
package/dist/mod.d.cts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Probe, ProbeOverrides } from "@openstatus/health";
|
|
2
|
+
|
|
3
|
+
//#region src/mod.d.ts
|
|
4
|
+
|
|
5
|
+
/** Probe name when `name` is unset. */
|
|
6
|
+
declare const kafkaDefaultName = "kafka";
|
|
7
|
+
/** What `describeCluster()` resolves to. */
|
|
8
|
+
interface KafkaClusterDescription {
|
|
9
|
+
/** The brokers currently in the cluster. */
|
|
10
|
+
readonly brokers: readonly {
|
|
11
|
+
readonly nodeId: number;
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
/** The subset of a KafkaJS `Admin` client the probe uses. */
|
|
15
|
+
interface KafkaLikeAdmin {
|
|
16
|
+
/** Fetch cluster metadata from the connected broker. */
|
|
17
|
+
describeCluster(): PromiseLike<KafkaClusterDescription>;
|
|
18
|
+
}
|
|
19
|
+
/** Options for `kafkaProbe()`. */
|
|
20
|
+
interface KafkaProbeOptions extends ProbeOverrides {
|
|
21
|
+
/** A connected `kafkajs` `Admin` client. */
|
|
22
|
+
readonly admin: KafkaLikeAdmin;
|
|
23
|
+
}
|
|
24
|
+
/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
|
|
25
|
+
declare function kafkaProbe(options: KafkaProbeOptions): Probe;
|
|
26
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
27
|
+
//#endregion
|
|
28
|
+
export { KafkaClusterDescription, KafkaLikeAdmin, KafkaProbeOptions, kafkaDefaultName, kafkaProbe };
|
|
29
|
+
//# sourceMappingURL=mod.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AA4CoC,cArBvB,gBAAA,GAqBuB,OAAA;;AAAyB,UAlB5C,uBAAA,CAkB4C;;;;;;;UAZ5C,cAAA;;qBAEI,YAAY;;;UAIhB,iBAAA,SAA0B;;kBAEzB;;;iBAIF,UAAA,UAAoB,oBAAoB"}
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Probe, ProbeOverrides } from "@openstatus/health";
|
|
2
|
+
|
|
3
|
+
//#region src/mod.d.ts
|
|
4
|
+
|
|
5
|
+
/** Probe name when `name` is unset. */
|
|
6
|
+
declare const kafkaDefaultName = "kafka";
|
|
7
|
+
/** What `describeCluster()` resolves to. */
|
|
8
|
+
interface KafkaClusterDescription {
|
|
9
|
+
/** The brokers currently in the cluster. */
|
|
10
|
+
readonly brokers: readonly {
|
|
11
|
+
readonly nodeId: number;
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
/** The subset of a KafkaJS `Admin` client the probe uses. */
|
|
15
|
+
interface KafkaLikeAdmin {
|
|
16
|
+
/** Fetch cluster metadata from the connected broker. */
|
|
17
|
+
describeCluster(): PromiseLike<KafkaClusterDescription>;
|
|
18
|
+
}
|
|
19
|
+
/** Options for `kafkaProbe()`. */
|
|
20
|
+
interface KafkaProbeOptions extends ProbeOverrides {
|
|
21
|
+
/** A connected `kafkajs` `Admin` client. */
|
|
22
|
+
readonly admin: KafkaLikeAdmin;
|
|
23
|
+
}
|
|
24
|
+
/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
|
|
25
|
+
declare function kafkaProbe(options: KafkaProbeOptions): Probe;
|
|
26
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
27
|
+
//#endregion
|
|
28
|
+
export { KafkaClusterDescription, KafkaLikeAdmin, KafkaProbeOptions, kafkaDefaultName, kafkaProbe };
|
|
29
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AA4CoC,cArBvB,gBAAA,GAqBuB,OAAA;;AAAyB,UAlB5C,uBAAA,CAkB4C;;;;;;;UAZ5C,cAAA;;qBAEI,YAAY;;;UAIhB,iBAAA,SAA0B;;kBAEzB;;;iBAIF,UAAA,UAAoB,oBAAoB"}
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ProbeConfigError } from "@openstatus/health";
|
|
2
|
+
|
|
3
|
+
//#region src/mod.ts
|
|
4
|
+
/** Probe name when `name` is unset. */
|
|
5
|
+
const kafkaDefaultName = "kafka";
|
|
6
|
+
/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
|
|
7
|
+
function kafkaProbe(options) {
|
|
8
|
+
const admin = options.admin;
|
|
9
|
+
if (typeof admin?.describeCluster !== "function") throw new ProbeConfigError("kafkaProbe", "admin", `must expose describeCluster(), got ${describe(admin)}`);
|
|
10
|
+
return {
|
|
11
|
+
name: options.name ?? kafkaDefaultName,
|
|
12
|
+
critical: options.critical ?? false,
|
|
13
|
+
timeoutMs: options.timeoutMs,
|
|
14
|
+
skip: options.skip,
|
|
15
|
+
run: async () => {
|
|
16
|
+
const cluster = await admin.describeCluster();
|
|
17
|
+
const brokers = cluster?.brokers;
|
|
18
|
+
if (!Array.isArray(brokers)) throw new Error("unexpected response shape");
|
|
19
|
+
if (brokers.length === 0) throw new Error("no brokers in cluster");
|
|
20
|
+
return { brokers: brokers.length };
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function describe(admin) {
|
|
25
|
+
if (admin == null) return String(admin);
|
|
26
|
+
if (typeof admin !== "object") return typeof admin;
|
|
27
|
+
const keys = Object.keys(admin);
|
|
28
|
+
return keys.length === 0 ? "an object with no keys" : `an object with keys ${keys.slice(0, 8).join(", ")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { kafkaDefaultName, kafkaProbe };
|
|
33
|
+
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.js","names":["options: KafkaProbeOptions","admin: KafkaLikeAdmin"],"sources":["../src/mod.ts"],"sourcesContent":["/**\n * Kafka probe for `@openstatus/health`: describes the cluster through a\n * connected KafkaJS-style `Admin` client and fails when no broker answers.\n *\n * ```ts\n * import { Kafka } from \"kafkajs\";\n * import { kafkaProbe } from \"@openstatus/health-kafka\";\n *\n * const admin = new Kafka({ brokers }).admin();\n * await admin.connect();\n * const probe = kafkaProbe({ admin });\n * ```\n *\n * @module\n */\n\nimport {\n type Probe,\n ProbeConfigError,\n type ProbeOverrides,\n} from \"@openstatus/health\";\n\n/** Probe name when `name` is unset. */\nexport const kafkaDefaultName = \"kafka\";\n\n/** What `describeCluster()` resolves to. */\nexport interface KafkaClusterDescription {\n /** The brokers currently in the cluster. */\n readonly brokers: readonly { readonly nodeId: number }[];\n}\n\n/** The subset of a KafkaJS `Admin` client the probe uses. */\nexport interface KafkaLikeAdmin {\n /** Fetch cluster metadata from the connected broker. */\n describeCluster(): PromiseLike<KafkaClusterDescription>;\n}\n\n/** Options for `kafkaProbe()`. */\nexport interface KafkaProbeOptions extends ProbeOverrides {\n /** A connected `kafkajs` `Admin` client. */\n readonly admin: KafkaLikeAdmin;\n}\n\n/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */\nexport function kafkaProbe(options: KafkaProbeOptions): Probe {\n const admin = options.admin;\n if (typeof admin?.describeCluster !== \"function\") {\n throw new ProbeConfigError(\n \"kafkaProbe\",\n \"admin\",\n `must expose describeCluster(), got ${describe(admin)}`,\n );\n }\n return {\n name: options.name ?? kafkaDefaultName,\n critical: options.critical ?? false,\n timeoutMs: options.timeoutMs,\n skip: options.skip,\n run: async () => {\n const cluster = await admin.describeCluster();\n const brokers = cluster?.brokers;\n if (!Array.isArray(brokers)) throw new Error(\"unexpected response shape\");\n if (brokers.length === 0) throw new Error(\"no brokers in cluster\");\n return { brokers: brokers.length };\n },\n };\n}\n\nfunction describe(admin: KafkaLikeAdmin): string {\n if (admin == null) return String(admin);\n if (typeof admin !== \"object\") return typeof admin;\n const keys = Object.keys(admin);\n return keys.length === 0\n ? \"an object with no keys\"\n : `an object with keys ${keys.slice(0, 8).join(\", \")}`;\n}\n"],"mappings":";;;;AAuBA,MAAa,mBAAmB;;AAqBhC,SAAgB,WAAWA,SAAmC;CAC5D,MAAM,QAAQ,QAAQ;AACtB,YAAW,OAAO,oBAAoB,WACpC,OAAM,IAAI,iBACR,cACA,UACC,qCAAqC,SAAS,MAAM,CAAC;AAG1D,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ,YAAY;EAC9B,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd,KAAK,YAAY;GACf,MAAM,UAAU,MAAM,MAAM,iBAAiB;GAC7C,MAAM,UAAU,SAAS;AACzB,QAAK,MAAM,QAAQ,QAAQ,CAAE,OAAM,IAAI,MAAM;AAC7C,OAAI,QAAQ,WAAW,EAAG,OAAM,IAAI,MAAM;AAC1C,UAAO,EAAE,SAAS,QAAQ,OAAQ;EACnC;CACF;AACF;AAED,SAAS,SAASC,OAA+B;AAC/C,KAAI,SAAS,KAAM,QAAO,OAAO,MAAM;AACvC,YAAW,UAAU,SAAU,eAAc;CAC7C,MAAM,OAAO,OAAO,KAAK,MAAM;AAC/B,QAAO,KAAK,WAAW,IACnB,4BACC,sBAAsB,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC;AACxD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openstatus/health-kafka",
|
|
3
|
+
"version": "0.1.4-dev.0",
|
|
4
|
+
"description": "Kafka probe for @openstatus/health",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"openstatus",
|
|
7
|
+
"health",
|
|
8
|
+
"healthcheck",
|
|
9
|
+
"kafka",
|
|
10
|
+
"kafkajs",
|
|
11
|
+
"messaging",
|
|
12
|
+
"streaming"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "openstatus",
|
|
17
|
+
"url": "https://www.openstatus.dev/"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/openstatusHQ/health",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/openstatusHQ/health.git",
|
|
23
|
+
"directory": "packages/kafka/"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/openstatusHQ/health/issues"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"module": "./dist/mod.js",
|
|
30
|
+
"main": "./dist/mod.cjs",
|
|
31
|
+
"types": "./dist/mod.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": {
|
|
35
|
+
"import": "./dist/mod.d.ts",
|
|
36
|
+
"require": "./dist/mod.d.cts"
|
|
37
|
+
},
|
|
38
|
+
"import": "./dist/mod.js",
|
|
39
|
+
"require": "./dist/mod.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"sideEffects": false,
|
|
44
|
+
"files": [
|
|
45
|
+
"dist/"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@openstatus/health": "^0.1.4-dev.0",
|
|
52
|
+
"kafkajs": ">=2.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"kafkajs": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"tsdown": "^0.12.7",
|
|
61
|
+
"typescript": "^5.8.3"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsdown",
|
|
65
|
+
"prepack": "tsdown",
|
|
66
|
+
"test": "node --experimental-transform-types --test"
|
|
67
|
+
}
|
|
68
|
+
}
|