@platformatic/kafka 1.19.0 → 1.21.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/dist/apis/admin/create-partitions-v1.d.ts +24 -0
- package/dist/apis/admin/create-partitions-v1.js +53 -0
- package/dist/apis/admin/create-partitions-v2.d.ts +24 -0
- package/dist/apis/admin/create-partitions-v2.js +54 -0
- package/dist/apis/admin/describe-configs-v2.d.ts +38 -0
- package/dist/apis/admin/describe-configs-v2.js +84 -0
- package/dist/apis/admin/describe-configs-v3.d.ts +38 -0
- package/dist/apis/admin/describe-configs-v3.js +84 -0
- package/dist/apis/admin/index.d.ts +4 -0
- package/dist/apis/admin/index.js +4 -0
- package/dist/apis/callbacks.js +1 -0
- package/dist/apis/consumer/fetch-v12.d.ts +46 -0
- package/dist/apis/consumer/fetch-v12.js +123 -0
- package/dist/apis/consumer/fetch-v13.d.ts +46 -0
- package/dist/apis/consumer/fetch-v13.js +123 -0
- package/dist/apis/consumer/fetch-v14.d.ts +46 -0
- package/dist/apis/consumer/fetch-v14.js +123 -0
- package/dist/apis/consumer/index.d.ts +4 -0
- package/dist/apis/consumer/index.js +4 -0
- package/dist/apis/consumer/offset-for-leader-epoch-v4.d.ts +29 -0
- package/dist/apis/consumer/offset-for-leader-epoch-v4.js +65 -0
- package/dist/apis/metadata/index.d.ts +3 -0
- package/dist/apis/metadata/index.js +3 -0
- package/dist/apis/metadata/metadata-v10.d.ts +37 -0
- package/dist/apis/metadata/metadata-v10.js +96 -0
- package/dist/apis/metadata/metadata-v11.d.ts +37 -0
- package/dist/apis/metadata/metadata-v11.js +96 -0
- package/dist/apis/metadata/metadata-v9.d.ts +37 -0
- package/dist/apis/metadata/metadata-v9.js +96 -0
- package/dist/apis/producer/index.d.ts +2 -0
- package/dist/apis/producer/index.js +2 -0
- package/dist/apis/producer/produce-v7.d.ts +29 -0
- package/dist/apis/producer/produce-v7.js +88 -0
- package/dist/apis/producer/produce-v8.d.ts +29 -0
- package/dist/apis/producer/produce-v8.js +101 -0
- package/dist/clients/admin/admin.js +16 -12
- package/dist/clients/admin/types.d.ts +4 -4
- package/dist/clients/base/base.d.ts +1 -2
- package/dist/clients/base/base.js +100 -98
- package/dist/clients/base/index.d.ts +1 -1
- package/dist/clients/base/index.js +1 -1
- package/dist/clients/consumer/consumer.js +5 -3
- package/dist/clients/consumer/messages-stream.d.ts +8 -0
- package/dist/clients/consumer/messages-stream.js +30 -1
- package/dist/clients/producer/producer.js +2 -2
- package/dist/network/connection.js +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -23,7 +23,6 @@ export const kClosed = Symbol('plt.kafka.base.closed');
|
|
|
23
23
|
export const kListApis = Symbol('plt.kafka.base.listApis');
|
|
24
24
|
export const kMetadata = Symbol('plt.kafka.base.metadata');
|
|
25
25
|
export const kCheckNotClosed = Symbol('plt.kafka.base.checkNotClosed');
|
|
26
|
-
export const kClearMetadata = Symbol('plt.kafka.base.clearMetadata');
|
|
27
26
|
export const kPerformWithRetry = Symbol('plt.kafka.base.performWithRetry');
|
|
28
27
|
export const kPerformDeduplicated = Symbol('plt.kafka.base.performDeduplicated');
|
|
29
28
|
export const kValidateOptions = Symbol('plt.kafka.base.validateOptions');
|
|
@@ -118,7 +117,7 @@ export class Base extends EventEmitter {
|
|
|
118
117
|
callback(validationError, undefined);
|
|
119
118
|
return callback[kCallbackPromise];
|
|
120
119
|
}
|
|
121
|
-
|
|
120
|
+
this[kMetadata](options, callback);
|
|
122
121
|
return callback[kCallbackPromise];
|
|
123
122
|
}
|
|
124
123
|
connectToBrokers(nodeIds, callback) {
|
|
@@ -209,101 +208,7 @@ export class Base extends EventEmitter {
|
|
|
209
208
|
}, callback);
|
|
210
209
|
}
|
|
211
210
|
[kMetadata](options, callback) {
|
|
212
|
-
|
|
213
|
-
let topicsToFetch = [];
|
|
214
|
-
// Determine which topics we need to fetch
|
|
215
|
-
if (!this.#metadata || options.forceUpdate) {
|
|
216
|
-
topicsToFetch = options.topics;
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
for (const topic of options.topics) {
|
|
220
|
-
const existingTopic = this.#metadata.topics.get(topic);
|
|
221
|
-
if (!existingTopic || existingTopic.lastUpdate < expiralDate) {
|
|
222
|
-
topicsToFetch.push(topic);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
// All topics are already up-to-date, simply return them
|
|
227
|
-
if (this.#metadata && !topicsToFetch.length && !options.forceUpdate) {
|
|
228
|
-
callback(null, {
|
|
229
|
-
...this.#metadata,
|
|
230
|
-
topics: new Map(options.topics.map(topic => [topic, this.#metadata.topics.get(topic)]))
|
|
231
|
-
});
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
const autocreateTopics = options.autocreateTopics ?? this[kOptions].autocreateTopics;
|
|
235
|
-
this[kPerformDeduplicated](
|
|
236
|
-
// Unique key to avoid mixing callbacks
|
|
237
|
-
`metadata-${options.topics.sort().join(',')}-${autocreateTopics}-${options.forceUpdate}`, deduplicateCallback => {
|
|
238
|
-
this[kPerformWithRetry]('metadata', retryCallback => {
|
|
239
|
-
this[kGetBootstrapConnection]((error, connection) => {
|
|
240
|
-
if (error) {
|
|
241
|
-
retryCallback(error, undefined);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
this[kGetApi]('Metadata', (error, api) => {
|
|
245
|
-
if (error) {
|
|
246
|
-
retryCallback(error, undefined);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
api(connection, topicsToFetch, autocreateTopics, true, retryCallback);
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
}, (error, metadata) => {
|
|
253
|
-
if (error) {
|
|
254
|
-
const hasStaleMetadata = error.findBy('hasStaleMetadata', true);
|
|
255
|
-
// Stale metadata, we need to fetch everything again
|
|
256
|
-
if (hasStaleMetadata) {
|
|
257
|
-
this[kClearMetadata]();
|
|
258
|
-
topicsToFetch = options.topics;
|
|
259
|
-
}
|
|
260
|
-
deduplicateCallback(error, undefined);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const lastUpdate = Date.now();
|
|
264
|
-
if (!this.#metadata) {
|
|
265
|
-
this.#metadata = {
|
|
266
|
-
id: metadata.clusterId,
|
|
267
|
-
brokers: new Map(),
|
|
268
|
-
topics: new Map(),
|
|
269
|
-
lastUpdate
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
this.#metadata.lastUpdate = lastUpdate;
|
|
274
|
-
}
|
|
275
|
-
const brokers = new Map();
|
|
276
|
-
// This should never change, but we act defensively here
|
|
277
|
-
for (const broker of metadata.brokers) {
|
|
278
|
-
const { host, port } = broker;
|
|
279
|
-
brokers.set(broker.nodeId, { host, port });
|
|
280
|
-
}
|
|
281
|
-
this.#metadata.brokers = brokers;
|
|
282
|
-
// Update all the topics in the cache
|
|
283
|
-
for (const { name, topicId: id, partitions: rawPartitions, isInternal } of metadata.topics) {
|
|
284
|
-
/* c8 ignore next 3 - Sometimes internal topics might be returned by Kafka */
|
|
285
|
-
if (isInternal) {
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
const partitions = [];
|
|
289
|
-
for (const rawPartition of rawPartitions.sort((a, b) => a.partitionIndex - b.partitionIndex)) {
|
|
290
|
-
partitions[rawPartition.partitionIndex] = {
|
|
291
|
-
leader: rawPartition.leaderId,
|
|
292
|
-
leaderEpoch: rawPartition.leaderEpoch,
|
|
293
|
-
replicas: rawPartition.replicaNodes
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
this.#metadata.topics.set(name, { id, partitions, partitionsCount: rawPartitions.length, lastUpdate });
|
|
297
|
-
}
|
|
298
|
-
// Now build the object to return
|
|
299
|
-
const updatedMetadata = {
|
|
300
|
-
...this.#metadata,
|
|
301
|
-
topics: new Map(options.topics.map(topic => [topic, this.#metadata.topics.get(topic)]))
|
|
302
|
-
};
|
|
303
|
-
this.emitWithDebug('client', 'metadata', updatedMetadata);
|
|
304
|
-
deduplicateCallback(null, updatedMetadata);
|
|
305
|
-
}, 0);
|
|
306
|
-
}, callback);
|
|
211
|
+
baseMetadataChannel.traceCallback(this.#performMetadata, 1, createDiagnosticContext({ client: this, operation: 'metadata' }), this, options, callback);
|
|
307
212
|
}
|
|
308
213
|
[kCheckNotClosed](callback) {
|
|
309
214
|
if (this[kClosed]) {
|
|
@@ -313,7 +218,7 @@ export class Base extends EventEmitter {
|
|
|
313
218
|
}
|
|
314
219
|
return false;
|
|
315
220
|
}
|
|
316
|
-
|
|
221
|
+
clearMetadata() {
|
|
317
222
|
this.#metadata = undefined;
|
|
318
223
|
}
|
|
319
224
|
[kPerformWithRetry](operationId, operation, callback, attempt = 0, errors = [], shouldSkipRetry) {
|
|
@@ -430,6 +335,103 @@ export class Base extends EventEmitter {
|
|
|
430
335
|
this[kClientType] = type;
|
|
431
336
|
notifyCreation(type, this);
|
|
432
337
|
}
|
|
338
|
+
#performMetadata(options, callback) {
|
|
339
|
+
const expiralDate = Date.now() - (options.metadataMaxAge ?? this[kOptions].metadataMaxAge);
|
|
340
|
+
let topicsToFetch = [];
|
|
341
|
+
// Determine which topics we need to fetch
|
|
342
|
+
if (!this.#metadata || options.forceUpdate) {
|
|
343
|
+
topicsToFetch = options.topics;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
for (const topic of options.topics) {
|
|
347
|
+
const existingTopic = this.#metadata.topics.get(topic);
|
|
348
|
+
if (!existingTopic || existingTopic.lastUpdate < expiralDate) {
|
|
349
|
+
topicsToFetch.push(topic);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// All topics are already up-to-date, simply return them
|
|
354
|
+
if (this.#metadata && !topicsToFetch.length && !options.forceUpdate) {
|
|
355
|
+
callback(null, {
|
|
356
|
+
...this.#metadata,
|
|
357
|
+
topics: new Map(options.topics.map(topic => [topic, this.#metadata.topics.get(topic)]))
|
|
358
|
+
});
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const autocreateTopics = options.autocreateTopics ?? this[kOptions].autocreateTopics;
|
|
362
|
+
this[kPerformDeduplicated](
|
|
363
|
+
// Unique key to avoid mixing callbacks
|
|
364
|
+
`metadata-${options.topics.sort().join(',')}-${autocreateTopics}-${options.forceUpdate}`, deduplicateCallback => {
|
|
365
|
+
this[kPerformWithRetry]('metadata', retryCallback => {
|
|
366
|
+
this[kGetBootstrapConnection]((error, connection) => {
|
|
367
|
+
if (error) {
|
|
368
|
+
retryCallback(error, undefined);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
this[kGetApi]('Metadata', (error, api) => {
|
|
372
|
+
if (error) {
|
|
373
|
+
retryCallback(error, undefined);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
api(connection, topicsToFetch, autocreateTopics, true, retryCallback);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
}, (error, metadata) => {
|
|
380
|
+
if (error) {
|
|
381
|
+
const hasStaleMetadata = error.findBy('hasStaleMetadata', true);
|
|
382
|
+
// Stale metadata, we need to fetch everything again
|
|
383
|
+
if (hasStaleMetadata) {
|
|
384
|
+
this.clearMetadata();
|
|
385
|
+
topicsToFetch = options.topics;
|
|
386
|
+
}
|
|
387
|
+
deduplicateCallback(error, undefined);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const lastUpdate = Date.now();
|
|
391
|
+
if (!this.#metadata) {
|
|
392
|
+
this.#metadata = {
|
|
393
|
+
id: metadata.clusterId,
|
|
394
|
+
brokers: new Map(),
|
|
395
|
+
topics: new Map(),
|
|
396
|
+
lastUpdate
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
this.#metadata.lastUpdate = lastUpdate;
|
|
401
|
+
}
|
|
402
|
+
const brokers = new Map();
|
|
403
|
+
// This should never change, but we act defensively here
|
|
404
|
+
for (const broker of metadata.brokers) {
|
|
405
|
+
const { host, port } = broker;
|
|
406
|
+
brokers.set(broker.nodeId, { host, port });
|
|
407
|
+
}
|
|
408
|
+
this.#metadata.brokers = brokers;
|
|
409
|
+
// Update all the topics in the cache
|
|
410
|
+
for (const { name, topicId: id, partitions: rawPartitions, isInternal } of metadata.topics) {
|
|
411
|
+
/* c8 ignore next 3 - Sometimes internal topics might be returned by Kafka */
|
|
412
|
+
if (isInternal) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const partitions = [];
|
|
416
|
+
for (const rawPartition of rawPartitions.sort((a, b) => a.partitionIndex - b.partitionIndex)) {
|
|
417
|
+
partitions[rawPartition.partitionIndex] = {
|
|
418
|
+
leader: rawPartition.leaderId,
|
|
419
|
+
leaderEpoch: rawPartition.leaderEpoch,
|
|
420
|
+
replicas: rawPartition.replicaNodes
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
this.#metadata.topics.set(name, { id, partitions, partitionsCount: rawPartitions.length, lastUpdate });
|
|
424
|
+
}
|
|
425
|
+
// Now build the object to return
|
|
426
|
+
const updatedMetadata = {
|
|
427
|
+
...this.#metadata,
|
|
428
|
+
topics: new Map(options.topics.map(topic => [topic, this.#metadata.topics.get(topic)]))
|
|
429
|
+
};
|
|
430
|
+
this.emitWithDebug('client', 'metadata', updatedMetadata);
|
|
431
|
+
deduplicateCallback(null, updatedMetadata);
|
|
432
|
+
}, 0);
|
|
433
|
+
}, callback);
|
|
434
|
+
}
|
|
433
435
|
#forwardEvents(source, events) {
|
|
434
436
|
for (const event of events) {
|
|
435
437
|
source.on(event, (...args) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { Base, kCheckNotClosed,
|
|
1
|
+
export { Base, kCheckNotClosed, kGetApi, kGetBootstrapConnection, kGetConnection, kListApis, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from './base.ts';
|
|
2
2
|
export * from './options.ts';
|
|
3
3
|
export * from './types.ts';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { Base, kCheckNotClosed,
|
|
1
|
+
export { Base, kCheckNotClosed, kGetApi, kGetBootstrapConnection, kGetConnection, kListApis, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "./base.js";
|
|
2
2
|
export * from "./options.js";
|
|
3
3
|
export * from "./types.js";
|
|
@@ -6,7 +6,7 @@ import { INT32_SIZE } from "../../protocol/definitions.js";
|
|
|
6
6
|
import { Reader } from "../../protocol/reader.js";
|
|
7
7
|
import { Writer } from "../../protocol/writer.js";
|
|
8
8
|
import { kAutocommit, kRefreshOffsetsAndFetch } from "../../symbols.js";
|
|
9
|
-
import { Base, kAfterCreate, kCheckNotClosed,
|
|
9
|
+
import { Base, kAfterCreate, kCheckNotClosed, kClosed, kCreateConnectionPool, kFetchConnections, kFormatValidationErrors, kGetApi, kGetBootstrapConnection, kGetConnection, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kPrometheus, kValidateOptions } from "../base/base.js";
|
|
10
10
|
import { defaultBaseOptions } from "../base/options.js";
|
|
11
11
|
import { ensureMetric } from "../metrics.js";
|
|
12
12
|
import { MessagesStream } from "./messages-stream.js";
|
|
@@ -271,7 +271,7 @@ export class Consumer extends Base {
|
|
|
271
271
|
// Now gather the last committed offsets from each stream
|
|
272
272
|
const committeds = new Map();
|
|
273
273
|
for (const stream of this.#streams) {
|
|
274
|
-
for (const [topic, offset] of stream.
|
|
274
|
+
for (const [topic, offset] of stream.offsetsCommitted) {
|
|
275
275
|
committeds.set(topic, offset);
|
|
276
276
|
}
|
|
277
277
|
}
|
|
@@ -933,6 +933,8 @@ export class Consumer extends Base {
|
|
|
933
933
|
callback(error, undefined);
|
|
934
934
|
return;
|
|
935
935
|
}
|
|
936
|
+
// This is for Azure Event Hubs compatibility, which does not respond with an error on the first join
|
|
937
|
+
this.memberId = response.memberId;
|
|
936
938
|
this.generationId = response.generationId;
|
|
937
939
|
this.#isLeader = response.leader === this.memberId;
|
|
938
940
|
this.#protocol = response.protocolName;
|
|
@@ -1212,7 +1214,7 @@ export class Consumer extends Base {
|
|
|
1212
1214
|
}
|
|
1213
1215
|
#handleMetadataError(error) {
|
|
1214
1216
|
if (error && error?.findBy('hasStaleMetadata', true)) {
|
|
1215
|
-
this
|
|
1217
|
+
this.clearMetadata();
|
|
1216
1218
|
}
|
|
1217
1219
|
return error;
|
|
1218
1220
|
}
|
|
@@ -11,6 +11,9 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
11
11
|
#private;
|
|
12
12
|
[kInstance]: number;
|
|
13
13
|
constructor(consumer: Consumer<Key, Value, HeaderKey, HeaderValue>, options: ConsumeOptions<Key, Value, HeaderKey, HeaderValue>);
|
|
14
|
+
get offsetsToFetch(): Map<string, bigint>;
|
|
15
|
+
get offsetsToCommit(): Map<string, CommitOptionsPartition>;
|
|
16
|
+
get offsetsCommitted(): Map<string, bigint>;
|
|
14
17
|
get committedOffsets(): Map<string, bigint>;
|
|
15
18
|
close(callback: CallbackWithPromise<void>): void;
|
|
16
19
|
close(): Promise<void>;
|
|
@@ -20,6 +23,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
20
23
|
pause(): this;
|
|
21
24
|
addListener(event: 'autocommit', listener: (err: Error, offsets: CommitOptionsPartition[]) => void): this;
|
|
22
25
|
addListener(event: 'fetch', listener: () => void): this;
|
|
26
|
+
addListener(event: 'offsets', listener: () => void): this;
|
|
23
27
|
addListener(event: 'data', listener: (message: Message<Key, Value, HeaderKey, HeaderValue>) => void): this;
|
|
24
28
|
addListener(event: 'close', listener: () => void): this;
|
|
25
29
|
addListener(event: 'end', listener: () => void): this;
|
|
@@ -29,6 +33,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
29
33
|
addListener(event: 'resume', listener: () => void): this;
|
|
30
34
|
on(event: 'autocommit', listener: (err: Error, offsets: CommitOptionsPartition[]) => void): this;
|
|
31
35
|
on(event: 'fetch', listener: () => void): this;
|
|
36
|
+
on(event: 'offsets', listener: () => void): this;
|
|
32
37
|
on(event: 'data', listener: (message: Message<Key, Value, HeaderKey, HeaderValue>) => void): this;
|
|
33
38
|
on(event: 'close', listener: () => void): this;
|
|
34
39
|
on(event: 'end', listener: () => void): this;
|
|
@@ -38,6 +43,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
38
43
|
on(event: 'resume', listener: () => void): this;
|
|
39
44
|
once(event: 'autocommit', listener: (err: Error, offsets: CommitOptionsPartition[]) => void): this;
|
|
40
45
|
once(event: 'fetch', listener: () => void): this;
|
|
46
|
+
once(event: 'offsets', listener: () => void): this;
|
|
41
47
|
once(event: 'data', listener: (message: Message<Key, Value, HeaderKey, HeaderValue>) => void): this;
|
|
42
48
|
once(event: 'close', listener: () => void): this;
|
|
43
49
|
once(event: 'end', listener: () => void): this;
|
|
@@ -47,6 +53,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
47
53
|
once(event: 'resume', listener: () => void): this;
|
|
48
54
|
prependListener(event: 'autocommit', listener: (err: Error, offsets: CommitOptionsPartition[]) => void): this;
|
|
49
55
|
prependListener(event: 'fetch', listener: () => void): this;
|
|
56
|
+
prependListener(event: 'offsets', listener: () => void): this;
|
|
50
57
|
prependListener(event: 'data', listener: (message: Message<Key, Value, HeaderKey, HeaderValue>) => void): this;
|
|
51
58
|
prependListener(event: 'close', listener: () => void): this;
|
|
52
59
|
prependListener(event: 'end', listener: () => void): this;
|
|
@@ -56,6 +63,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
56
63
|
prependListener(event: 'resume', listener: () => void): this;
|
|
57
64
|
prependOnceListener(event: 'autocommit', listener: (err: Error, offsets: CommitOptionsPartition[]) => void): this;
|
|
58
65
|
prependOnceListener(event: 'fetch', listener: () => void): this;
|
|
66
|
+
prependOnceListener(event: 'offsets', listener: () => void): this;
|
|
59
67
|
prependOnceListener(event: 'data', listener: (message: Message<Key, Value, HeaderKey, HeaderValue>) => void): this;
|
|
60
68
|
prependOnceListener(event: 'close', listener: () => void): this;
|
|
61
69
|
prependOnceListener(event: 'end', listener: () => void): this;
|
|
@@ -53,7 +53,7 @@ export class MessagesStream extends Readable {
|
|
|
53
53
|
if (!offsets && mode === MessagesStreamModes.MANUAL) {
|
|
54
54
|
throw new UserError('Must specify offsets when the stream mode is MANUAL.');
|
|
55
55
|
}
|
|
56
|
-
/* c8 ignore next - Unless is initialized directly, highWaterMark is always defined */
|
|
56
|
+
/* c8 ignore next 4 - Unless is initialized directly, highWaterMark is always defined */
|
|
57
57
|
super({
|
|
58
58
|
objectMode: true,
|
|
59
59
|
highWaterMark: maxFetches ?? options.highWaterMark ?? defaultConsumerOptions.highWaterMark
|
|
@@ -98,6 +98,7 @@ export class MessagesStream extends Readable {
|
|
|
98
98
|
// will have changed so we may have gone from last with no assignments to
|
|
99
99
|
// having some.
|
|
100
100
|
this.#consumer.on('consumer:group:join', () => {
|
|
101
|
+
this.#offsetsCommitted.clear();
|
|
101
102
|
this.#refreshOffsets((error) => {
|
|
102
103
|
/* c8 ignore next 4 - Hard to test */
|
|
103
104
|
if (error) {
|
|
@@ -112,6 +113,20 @@ export class MessagesStream extends Readable {
|
|
|
112
113
|
}
|
|
113
114
|
notifyCreation('messages-stream', this);
|
|
114
115
|
}
|
|
116
|
+
/* c8 ignore next 3 - Simple getter */
|
|
117
|
+
get offsetsToFetch() {
|
|
118
|
+
return this.#offsetsToFetch;
|
|
119
|
+
}
|
|
120
|
+
/* c8 ignore next 3 - Simple getter */
|
|
121
|
+
get offsetsToCommit() {
|
|
122
|
+
return this.#offsetsToCommit;
|
|
123
|
+
}
|
|
124
|
+
/* c8 ignore next 3 - Simple getter */
|
|
125
|
+
get offsetsCommitted() {
|
|
126
|
+
return this.#offsetsCommitted;
|
|
127
|
+
}
|
|
128
|
+
// TODO: This is deprecated alias, remove in future major version
|
|
129
|
+
/* c8 ignore next 3 - Simple getter */
|
|
115
130
|
get committedOffsets() {
|
|
116
131
|
return this.#offsetsCommitted;
|
|
117
132
|
}
|
|
@@ -525,6 +540,20 @@ export class MessagesStream extends Readable {
|
|
|
525
540
|
}
|
|
526
541
|
}
|
|
527
542
|
}
|
|
543
|
+
// Rebuild the list of offsetsCommitted (which is used for consumer lag) out of the offsets to fetch
|
|
544
|
+
for (const topic of this.#topics) {
|
|
545
|
+
const assignment = this.#assignmentsForTopic(topic);
|
|
546
|
+
// This consumer has no assignment for the topic, continue
|
|
547
|
+
if (!assignment) {
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
const partitions = assignment.partitions;
|
|
551
|
+
for (const partition of partitions) {
|
|
552
|
+
const committed = this.#offsetsToFetch.get(`${topic}:${partition}`);
|
|
553
|
+
this.#offsetsCommitted.set(`${topic}:${partition}`, committed - 1n);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
this.emit('offsets');
|
|
528
557
|
callback(null);
|
|
529
558
|
}
|
|
530
559
|
#assignmentsForTopic(topic) {
|
|
@@ -4,7 +4,7 @@ import { createDiagnosticContext, producerInitIdempotentChannel, producerSendsCh
|
|
|
4
4
|
import { UserError } from "../../errors.js";
|
|
5
5
|
import { murmur2 } from "../../protocol/murmur2.js";
|
|
6
6
|
import { NumericMap } from "../../utils.js";
|
|
7
|
-
import { Base, kAfterCreate, kCheckNotClosed,
|
|
7
|
+
import { Base, kAfterCreate, kCheckNotClosed, kClosed, kGetApi, kGetBootstrapConnection, kGetConnection, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kPrometheus, kValidateOptions } from "../base/base.js";
|
|
8
8
|
import { ensureMetric } from "../metrics.js";
|
|
9
9
|
import { produceOptionsValidator, producerOptionsValidator, sendOptionsValidator } from "./options.js";
|
|
10
10
|
// Don't move this function as being in the same file will enable V8 to remove.
|
|
@@ -311,7 +311,7 @@ export class Producer extends Base {
|
|
|
311
311
|
// since the partition is already set, it should attempt on the new destination
|
|
312
312
|
const hasStaleMetadata = error.findBy('hasStaleMetadata', true);
|
|
313
313
|
if (hasStaleMetadata && repeatOnStaleMetadata) {
|
|
314
|
-
this
|
|
314
|
+
this.clearMetadata();
|
|
315
315
|
this.#performSingleDestinationSend(topics, messages, timeout, acks, autocreateTopics, false, produceOptions, callback);
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
@@ -61,7 +61,7 @@ export class Connection extends EventEmitter {
|
|
|
61
61
|
this.#correlationId = 0;
|
|
62
62
|
this.#nextMessage = 0;
|
|
63
63
|
this.#afterDrainRequests = [];
|
|
64
|
-
this.#requestsQueue = fastq((op, cb) => op(cb), this.#options.maxInflights);
|
|
64
|
+
this.#requestsQueue = fastq((op, cb) => op(cb), this.#options.maxInflights ?? defaultOptions.maxInflights);
|
|
65
65
|
this.#inflightRequests = new Map();
|
|
66
66
|
this.#responseBuffer = new DynamicBuffer();
|
|
67
67
|
this.#responseReader = new Reader(this.#responseBuffer);
|
|
@@ -230,7 +230,7 @@ export class Connection extends EventEmitter {
|
|
|
230
230
|
catch (err) {
|
|
231
231
|
diagnostic.error = err;
|
|
232
232
|
connectionsApiChannel.error.publish(diagnostic);
|
|
233
|
-
|
|
233
|
+
return callback(err, undefined);
|
|
234
234
|
}
|
|
235
235
|
writer.appendFrom(payload).prependLength();
|
|
236
236
|
const request = {
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = "@platformatic/kafka";
|
|
2
|
-
export const version = "1.
|
|
2
|
+
export const version = "1.21.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/kafka",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Modern and performant client for Apache Kafka",
|
|
5
5
|
"homepage": "https://github.com/platformatic/kafka",
|
|
6
6
|
"author": "Platformatic Inc. <oss@platformatic.dev> (https://platformatic.dev)",
|