@forklaunch/implementation-worker-kafka 0.8.6 → 0.9.1
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/lib/consumers/index.d.mts +3 -1
- package/lib/consumers/index.d.ts +3 -1
- package/lib/consumers/index.js +26 -3
- package/lib/consumers/index.mjs +26 -3
- package/lib/domain/schemas/index.js +5 -5
- package/lib/domain/schemas/index.mjs +5 -5
- package/lib/eject/consumers/kafkaWorker.consumer.ts +41 -3
- package/package.json +7 -7
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OpenTelemetryCollector, MetricsDefinition } from '@forklaunch/core/http';
|
|
1
2
|
import { WorkerConsumer } from '@forklaunch/interfaces-worker/interfaces';
|
|
2
3
|
import { WorkerEventEntity, WorkerProcessFunction, WorkerFailureHandler } from '@forklaunch/interfaces-worker/types';
|
|
3
4
|
import { KafkaWorkerOptions } from '../domain/types/index.mjs';
|
|
@@ -11,7 +12,8 @@ declare class KafkaWorkerConsumer<EventEntity extends WorkerEventEntity, Options
|
|
|
11
12
|
protected readonly options: Options;
|
|
12
13
|
protected readonly processEventsFunction: WorkerProcessFunction<EventEntity>;
|
|
13
14
|
protected readonly failureHandler: WorkerFailureHandler<EventEntity>;
|
|
14
|
-
|
|
15
|
+
protected readonly openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>;
|
|
16
|
+
constructor(queueName: string, options: Options, processEventsFunction: WorkerProcessFunction<EventEntity>, failureHandler: WorkerFailureHandler<EventEntity>, openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>);
|
|
15
17
|
private setupConsumer;
|
|
16
18
|
peekEvents(): Promise<EventEntity[]>;
|
|
17
19
|
start(): Promise<void>;
|
package/lib/consumers/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OpenTelemetryCollector, MetricsDefinition } from '@forklaunch/core/http';
|
|
1
2
|
import { WorkerConsumer } from '@forklaunch/interfaces-worker/interfaces';
|
|
2
3
|
import { WorkerEventEntity, WorkerProcessFunction, WorkerFailureHandler } from '@forklaunch/interfaces-worker/types';
|
|
3
4
|
import { KafkaWorkerOptions } from '../domain/types/index.js';
|
|
@@ -11,7 +12,8 @@ declare class KafkaWorkerConsumer<EventEntity extends WorkerEventEntity, Options
|
|
|
11
12
|
protected readonly options: Options;
|
|
12
13
|
protected readonly processEventsFunction: WorkerProcessFunction<EventEntity>;
|
|
13
14
|
protected readonly failureHandler: WorkerFailureHandler<EventEntity>;
|
|
14
|
-
|
|
15
|
+
protected readonly openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>;
|
|
16
|
+
constructor(queueName: string, options: Options, processEventsFunction: WorkerProcessFunction<EventEntity>, failureHandler: WorkerFailureHandler<EventEntity>, openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>);
|
|
15
17
|
private setupConsumer;
|
|
16
18
|
peekEvents(): Promise<EventEntity[]>;
|
|
17
19
|
start(): Promise<void>;
|
package/lib/consumers/index.js
CHANGED
|
@@ -35,7 +35,8 @@ var KafkaWorkerConsumer = class {
|
|
|
35
35
|
options;
|
|
36
36
|
processEventsFunction;
|
|
37
37
|
failureHandler;
|
|
38
|
-
|
|
38
|
+
openTelemetryCollector;
|
|
39
|
+
constructor(queueName, options, processEventsFunction, failureHandler, openTelemetryCollector) {
|
|
39
40
|
this.queueName = queueName;
|
|
40
41
|
this.options = options;
|
|
41
42
|
this.processEventsFunction = processEventsFunction;
|
|
@@ -48,6 +49,7 @@ var KafkaWorkerConsumer = class {
|
|
|
48
49
|
this.consumer = this.kafka.consumer({
|
|
49
50
|
groupId: this.options.groupId
|
|
50
51
|
});
|
|
52
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
|
51
53
|
}
|
|
52
54
|
async setupConsumer() {
|
|
53
55
|
await this.consumer.connect();
|
|
@@ -163,8 +165,29 @@ var KafkaWorkerConsumer = class {
|
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
async start() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
+
const maxAttempts = 30;
|
|
169
|
+
const delayMs = 2e3;
|
|
170
|
+
let attempt = 1;
|
|
171
|
+
while (attempt <= maxAttempts) {
|
|
172
|
+
try {
|
|
173
|
+
await this.setupConsumer();
|
|
174
|
+
await this.producer.connect();
|
|
175
|
+
return;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const err = error;
|
|
178
|
+
const isUnknownTopic = err?.code === 3 || err?.type === "UNKNOWN_TOPIC_OR_PARTITION" || (err?.message || "").includes(
|
|
179
|
+
"This server does not host this topic-partition"
|
|
180
|
+
);
|
|
181
|
+
if (!isUnknownTopic || attempt >= maxAttempts) {
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
this.openTelemetryCollector.warn(
|
|
185
|
+
`Kafka not ready for topic ${this.queueName} (attempt ${attempt}/${maxAttempts}). Retrying in ${delayMs}ms...`
|
|
186
|
+
);
|
|
187
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
188
|
+
attempt += 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
168
191
|
}
|
|
169
192
|
async close() {
|
|
170
193
|
await this.producer.disconnect();
|
package/lib/consumers/index.mjs
CHANGED
|
@@ -9,7 +9,8 @@ var KafkaWorkerConsumer = class {
|
|
|
9
9
|
options;
|
|
10
10
|
processEventsFunction;
|
|
11
11
|
failureHandler;
|
|
12
|
-
|
|
12
|
+
openTelemetryCollector;
|
|
13
|
+
constructor(queueName, options, processEventsFunction, failureHandler, openTelemetryCollector) {
|
|
13
14
|
this.queueName = queueName;
|
|
14
15
|
this.options = options;
|
|
15
16
|
this.processEventsFunction = processEventsFunction;
|
|
@@ -22,6 +23,7 @@ var KafkaWorkerConsumer = class {
|
|
|
22
23
|
this.consumer = this.kafka.consumer({
|
|
23
24
|
groupId: this.options.groupId
|
|
24
25
|
});
|
|
26
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
|
25
27
|
}
|
|
26
28
|
async setupConsumer() {
|
|
27
29
|
await this.consumer.connect();
|
|
@@ -137,8 +139,29 @@ var KafkaWorkerConsumer = class {
|
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
async start() {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
const maxAttempts = 30;
|
|
143
|
+
const delayMs = 2e3;
|
|
144
|
+
let attempt = 1;
|
|
145
|
+
while (attempt <= maxAttempts) {
|
|
146
|
+
try {
|
|
147
|
+
await this.setupConsumer();
|
|
148
|
+
await this.producer.connect();
|
|
149
|
+
return;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const err = error;
|
|
152
|
+
const isUnknownTopic = err?.code === 3 || err?.type === "UNKNOWN_TOPIC_OR_PARTITION" || (err?.message || "").includes(
|
|
153
|
+
"This server does not host this topic-partition"
|
|
154
|
+
);
|
|
155
|
+
if (!isUnknownTopic || attempt >= maxAttempts) {
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
this.openTelemetryCollector.warn(
|
|
159
|
+
`Kafka not ready for topic ${this.queueName} (attempt ${attempt}/${maxAttempts}). Retrying in ${delayMs}ms...`
|
|
160
|
+
);
|
|
161
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
162
|
+
attempt += 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
142
165
|
}
|
|
143
166
|
async close() {
|
|
144
167
|
await this.producer.disconnect();
|
|
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(schemas_exports);
|
|
|
28
28
|
// domain/schemas/kafka.schema.ts
|
|
29
29
|
var import_internal = require("@forklaunch/internal");
|
|
30
30
|
|
|
31
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
31
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/typebox/index.mjs
|
|
32
32
|
var typebox_exports = {};
|
|
33
33
|
__export(typebox_exports, {
|
|
34
34
|
SchemaValidator: () => SchemaValidator,
|
|
@@ -68,7 +68,7 @@ __export(typebox_exports, {
|
|
|
68
68
|
});
|
|
69
69
|
__reExport(typebox_exports, require("@sinclair/typebox"));
|
|
70
70
|
|
|
71
|
-
// ../../../node_modules/.pnpm/@forklaunch+common@0.6.
|
|
71
|
+
// ../../../node_modules/.pnpm/@forklaunch+common@0.6.23/node_modules/@forklaunch/common/lib/index.mjs
|
|
72
72
|
function deepCloneWithoutUndefined(obj, seen = /* @__PURE__ */ new WeakMap()) {
|
|
73
73
|
if (obj === null || obj === void 0) {
|
|
74
74
|
return obj;
|
|
@@ -148,7 +148,7 @@ var InMemoryBlob = class extends Blob {
|
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
151
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/typebox/index.mjs
|
|
152
152
|
var import_typebox = require("@sinclair/typebox");
|
|
153
153
|
var import_compiler = require("@sinclair/typebox/compiler");
|
|
154
154
|
var import_errors = require("@sinclair/typebox/errors");
|
|
@@ -736,7 +736,7 @@ var KafkaWorkerOptionsSchema = {
|
|
|
736
736
|
peekCount: number
|
|
737
737
|
};
|
|
738
738
|
|
|
739
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
739
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/zod/index.mjs
|
|
740
740
|
var import_v3 = require("zod/v3");
|
|
741
741
|
|
|
742
742
|
// ../../../node_modules/.pnpm/ts-deepmerge@7.0.3/node_modules/ts-deepmerge/esm/index.js
|
|
@@ -786,7 +786,7 @@ merge.withOptions = (options, ...objects) => {
|
|
|
786
786
|
return result;
|
|
787
787
|
};
|
|
788
788
|
|
|
789
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
789
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/zod/index.mjs
|
|
790
790
|
var import_v32 = require("zod/v3");
|
|
791
791
|
function extendApi(schema, schemaObject = {}) {
|
|
792
792
|
const This = schema.constructor;
|
|
@@ -19,7 +19,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
19
19
|
// domain/schemas/kafka.schema.ts
|
|
20
20
|
import { serviceSchemaResolver } from "@forklaunch/internal";
|
|
21
21
|
|
|
22
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
22
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/typebox/index.mjs
|
|
23
23
|
var typebox_exports = {};
|
|
24
24
|
__export(typebox_exports, {
|
|
25
25
|
SchemaValidator: () => SchemaValidator,
|
|
@@ -60,7 +60,7 @@ __export(typebox_exports, {
|
|
|
60
60
|
__reExport(typebox_exports, typebox_star);
|
|
61
61
|
import * as typebox_star from "@sinclair/typebox";
|
|
62
62
|
|
|
63
|
-
// ../../../node_modules/.pnpm/@forklaunch+common@0.6.
|
|
63
|
+
// ../../../node_modules/.pnpm/@forklaunch+common@0.6.23/node_modules/@forklaunch/common/lib/index.mjs
|
|
64
64
|
function deepCloneWithoutUndefined(obj, seen = /* @__PURE__ */ new WeakMap()) {
|
|
65
65
|
if (obj === null || obj === void 0) {
|
|
66
66
|
return obj;
|
|
@@ -140,7 +140,7 @@ var InMemoryBlob = class extends Blob {
|
|
|
140
140
|
}
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
143
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/typebox/index.mjs
|
|
144
144
|
import {
|
|
145
145
|
FormatRegistry,
|
|
146
146
|
Kind,
|
|
@@ -738,7 +738,7 @@ var KafkaWorkerOptionsSchema = {
|
|
|
738
738
|
peekCount: number
|
|
739
739
|
};
|
|
740
740
|
|
|
741
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
741
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/zod/index.mjs
|
|
742
742
|
import {
|
|
743
743
|
z as z2,
|
|
744
744
|
ZodType
|
|
@@ -791,7 +791,7 @@ merge.withOptions = (options, ...objects) => {
|
|
|
791
791
|
return result;
|
|
792
792
|
};
|
|
793
793
|
|
|
794
|
-
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.
|
|
794
|
+
// ../../../node_modules/.pnpm/@forklaunch+validator@0.10.23/node_modules/@forklaunch/validator/lib/src/zod/index.mjs
|
|
795
795
|
import { z } from "zod/v3";
|
|
796
796
|
function extendApi(schema, schemaObject = {}) {
|
|
797
797
|
const This = schema.constructor;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MetricsDefinition,
|
|
3
|
+
OpenTelemetryCollector
|
|
4
|
+
} from '@forklaunch/core/http';
|
|
1
5
|
import { WorkerConsumer } from '@forklaunch/interfaces-worker/interfaces';
|
|
2
6
|
import {
|
|
3
7
|
WorkerEventEntity,
|
|
@@ -20,12 +24,14 @@ export class KafkaWorkerConsumer<
|
|
|
20
24
|
protected readonly options: Options;
|
|
21
25
|
protected readonly processEventsFunction: WorkerProcessFunction<EventEntity>;
|
|
22
26
|
protected readonly failureHandler: WorkerFailureHandler<EventEntity>;
|
|
27
|
+
protected readonly openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>;
|
|
23
28
|
|
|
24
29
|
constructor(
|
|
25
30
|
queueName: string,
|
|
26
31
|
options: Options,
|
|
27
32
|
processEventsFunction: WorkerProcessFunction<EventEntity>,
|
|
28
|
-
failureHandler: WorkerFailureHandler<EventEntity
|
|
33
|
+
failureHandler: WorkerFailureHandler<EventEntity>,
|
|
34
|
+
openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>
|
|
29
35
|
) {
|
|
30
36
|
this.queueName = queueName;
|
|
31
37
|
this.options = options;
|
|
@@ -40,6 +46,7 @@ export class KafkaWorkerConsumer<
|
|
|
40
46
|
this.consumer = this.kafka.consumer({
|
|
41
47
|
groupId: this.options.groupId
|
|
42
48
|
});
|
|
49
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
private async setupConsumer() {
|
|
@@ -179,8 +186,39 @@ export class KafkaWorkerConsumer<
|
|
|
179
186
|
}
|
|
180
187
|
|
|
181
188
|
async start(): Promise<void> {
|
|
182
|
-
|
|
183
|
-
|
|
189
|
+
const maxAttempts = 30;
|
|
190
|
+
const delayMs = 2000;
|
|
191
|
+
let attempt = 1;
|
|
192
|
+
|
|
193
|
+
while (attempt <= maxAttempts) {
|
|
194
|
+
try {
|
|
195
|
+
await this.setupConsumer();
|
|
196
|
+
await this.producer.connect();
|
|
197
|
+
return;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const err = error as Error & {
|
|
200
|
+
code?: number;
|
|
201
|
+
type?: string;
|
|
202
|
+
message?: string;
|
|
203
|
+
};
|
|
204
|
+
const isUnknownTopic =
|
|
205
|
+
err?.code === 3 ||
|
|
206
|
+
err?.type === 'UNKNOWN_TOPIC_OR_PARTITION' ||
|
|
207
|
+
(err?.message || '').includes(
|
|
208
|
+
'This server does not host this topic-partition'
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (!isUnknownTopic || attempt >= maxAttempts) {
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.openTelemetryCollector.warn(
|
|
216
|
+
`Kafka not ready for topic ${this.queueName} (attempt ${attempt}/${maxAttempts}). Retrying in ${delayMs}ms...`
|
|
217
|
+
);
|
|
218
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
219
|
+
attempt += 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
184
222
|
}
|
|
185
223
|
|
|
186
224
|
async close(): Promise<void> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forklaunch/implementation-worker-kafka",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Kafka implementation for forklaunch workers",
|
|
5
5
|
"homepage": "https://github.com/forklaunch/forklaunch-js#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -42,20 +42,20 @@
|
|
|
42
42
|
"lib/**"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@forklaunch/core": "^0.
|
|
46
|
-
"@forklaunch/internal": "^0.3.
|
|
45
|
+
"@forklaunch/core": "^0.16.1",
|
|
46
|
+
"@forklaunch/internal": "^0.3.23",
|
|
47
47
|
"@sinclair/typebox": "^0.34.41",
|
|
48
48
|
"kafkajs": "^2.2.4",
|
|
49
49
|
"zod": "^4.1.12",
|
|
50
|
-
"@forklaunch/interfaces-worker": "0.7.
|
|
50
|
+
"@forklaunch/interfaces-worker": "0.7.7"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
53
|
+
"@typescript/native-preview": "7.0.0-dev.20251117.1",
|
|
54
54
|
"depcheck": "^1.4.7",
|
|
55
|
-
"eslint": "^9.
|
|
55
|
+
"eslint": "^9.39.1",
|
|
56
56
|
"prettier": "^3.6.2",
|
|
57
57
|
"typedoc": "^0.28.14",
|
|
58
|
-
"typescript-eslint": "^8.46.
|
|
58
|
+
"typescript-eslint": "^8.46.4"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "tsc --noEmit && tsup producers/index.ts consumers/index.ts domain/schemas/index.ts domain/types/index.ts --format cjs,esm --no-splitting --dts --tsconfig tsconfig.json --out-dir lib --clean && if [ -f eject-package.bash ]; then pnpm package:eject; fi",
|