@platformatic/kafka 1.33.2 → 1.35.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/alter-partition-reassignments-v1.js +1 -0
- package/dist/clients/admin/admin.d.ts +1 -1
- package/dist/clients/admin/admin.js +2 -1
- package/dist/clients/base/base.d.ts +2 -0
- package/dist/clients/base/base.js +17 -4
- package/dist/clients/consumer/consumer.js +25 -2
- package/dist/clients/consumer/messages-stream.d.ts +1 -0
- package/dist/clients/consumer/messages-stream.js +41 -14
- package/dist/clients/consumer/options.d.ts +16 -0
- package/dist/clients/consumer/options.js +1 -0
- package/dist/clients/consumer/types.d.ts +1 -0
- package/dist/clients/producer/partitioners.js +2 -0
- package/dist/clients/producer/producer.d.ts +6 -0
- package/dist/clients/producer/producer.js +125 -24
- package/dist/clients/producer/types.d.ts +5 -2
- package/dist/errors.js +1 -1
- package/dist/network/connection-pool.d.ts +3 -0
- package/dist/network/connection-pool.js +9 -0
- package/dist/network/connection.js +1 -0
- package/dist/typescript-4/dist/clients/admin/admin.d.ts +1 -1
- package/dist/typescript-4/dist/clients/base/base.d.ts +2 -0
- package/dist/typescript-4/dist/clients/consumer/messages-stream.d.ts +1 -0
- package/dist/typescript-4/dist/clients/consumer/options.d.ts +16 -0
- package/dist/typescript-4/dist/clients/consumer/types.d.ts +1 -0
- package/dist/typescript-4/dist/clients/producer/producer.d.ts +6 -0
- package/dist/typescript-4/dist/clients/producer/types.d.ts +5 -2
- package/dist/typescript-4/dist/network/connection-pool.d.ts +3 -0
- package/dist/version.js +1 -1
- package/package.json +19 -17
|
@@ -39,6 +39,7 @@ export function parseResponse(_correlationId, apiKey, apiVersion, reader) {
|
|
|
39
39
|
const throttleTimeMs = reader.readInt32();
|
|
40
40
|
const errorCode = reader.readInt16();
|
|
41
41
|
const errorMessage = reader.readNullableString();
|
|
42
|
+
/* c8 ignore next 3 - Hard to test */
|
|
42
43
|
if (errorCode !== 0) {
|
|
43
44
|
errors.push(['', [errorCode, errorMessage]]);
|
|
44
45
|
}
|
|
@@ -5,7 +5,7 @@ import { type CallbackWithPromise } from '../../apis/callbacks.ts';
|
|
|
5
5
|
import { type Callback } from '../../apis/definitions.ts';
|
|
6
6
|
import { type Acl } from '../../apis/types.ts';
|
|
7
7
|
import { Base } from '../base/base.ts';
|
|
8
|
-
import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type
|
|
8
|
+
import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type DeletedRecordsTopic, type DeleteGroupsOptions, type DeleteRecordsOptions, type DeleteTopicsOptions, type DescribeAclsOptions, type DescribeClientQuotasOptions, type DescribeConfigsOptions, type DescribeGroupsOptions, type DescribeLogDirsOptions, type FindCoordinatorOptions, type FindCoordinatorResult, type Group, type GroupBase, type IncrementalAlterConfigsOptions, type ListConsumerGroupOffsetsGroup, type ListConsumerGroupOffsetsOptions, type ListedOffsetsTopic, type ListGroupsOptions, type ListTopicsOptions, type RemoveMembersFromConsumerGroupOptions } from './types.ts';
|
|
9
9
|
export declare class Admin extends Base<AdminOptions> {
|
|
10
10
|
#private;
|
|
11
11
|
constructor(options: AdminOptions);
|
|
@@ -4,7 +4,7 @@ import { adminAclsChannel, adminClientQuotasChannel, adminConfigsChannel, adminC
|
|
|
4
4
|
import { MultipleErrors, UserError } from "../../errors.js";
|
|
5
5
|
import { Reader } from "../../protocol/reader.js";
|
|
6
6
|
import { Base, kAfterCreate, kCheckNotClosed, kConnections, kGetApi, kGetBootstrapConnection, kGetConnection, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "../base/base.js";
|
|
7
|
-
import { adminListOffsetsOptionsValidator, alterClientQuotasOptionsValidator, alterConfigsOptionsValidator, alterConsumerGroupOffsetsOptionsValidator, createAclsOptionsValidator, createPartitionsOptionsValidator, createTopicsOptionsValidator, deleteAclsOptionsValidator, deleteConsumerGroupOffsetsOptionsValidator,
|
|
7
|
+
import { adminListOffsetsOptionsValidator, alterClientQuotasOptionsValidator, alterConfigsOptionsValidator, alterConsumerGroupOffsetsOptionsValidator, createAclsOptionsValidator, createPartitionsOptionsValidator, createTopicsOptionsValidator, deleteAclsOptionsValidator, deleteConsumerGroupOffsetsOptionsValidator, deleteGroupsOptionsValidator, deleteRecordsOptionsValidator, deleteTopicsOptionsValidator, describeAclsOptionsValidator, describeClientQuotasOptionsValidator, describeConfigsOptionsValidator, describeGroupsOptionsValidator, describeLogDirsOptionsValidator, findCoordinatorOptionsValidator, incrementalAlterConfigsOptionsValidator, listConsumerGroupOffsetsOptionsValidator, listGroupsOptionsValidator, listTopicsOptionsValidator, removeMembersFromConsumerGroupOptionsValidator } from "./options.js";
|
|
8
8
|
export class Admin extends Base {
|
|
9
9
|
#controller = null;
|
|
10
10
|
constructor(options) {
|
|
@@ -1391,6 +1391,7 @@ export class Admin extends Base {
|
|
|
1391
1391
|
// topics.get(topic.name) must be defined as the metadata request was successful
|
|
1392
1392
|
const topicData = topics.get(topic.name);
|
|
1393
1393
|
const targetPartitionData = topicData.partitions[partition.partitionIndex];
|
|
1394
|
+
/* c8 ignore next 4 - Hard to test */
|
|
1394
1395
|
if (!targetPartitionData) {
|
|
1395
1396
|
callback(new UserError(`Unknown partition ${partition.partitionIndex} for topic ${topic.name}.`));
|
|
1396
1397
|
return;
|
|
@@ -66,6 +66,8 @@ export declare class Base<OptionsType extends BaseOptions = BaseOptions, EventsT
|
|
|
66
66
|
get closed(): boolean;
|
|
67
67
|
get type(): ClientType;
|
|
68
68
|
get context(): unknown;
|
|
69
|
+
get currentMetadata(): ClusterMetadata | undefined;
|
|
70
|
+
get connections(): ConnectionPool;
|
|
69
71
|
emitWithDebug(section: string | null, name: string, ...args: any[]): boolean;
|
|
70
72
|
close(callback: CallbackWithPromise<void>): void;
|
|
71
73
|
close(): Promise<void>;
|
|
@@ -90,6 +90,12 @@ export class Base extends TypedEventEmitter {
|
|
|
90
90
|
get context() {
|
|
91
91
|
return this[kContext];
|
|
92
92
|
}
|
|
93
|
+
get currentMetadata() {
|
|
94
|
+
return this.#metadata;
|
|
95
|
+
}
|
|
96
|
+
get connections() {
|
|
97
|
+
return this[kConnections];
|
|
98
|
+
}
|
|
93
99
|
emitWithDebug(section, name, ...args) {
|
|
94
100
|
if (!section) {
|
|
95
101
|
return this.emit(name, ...args);
|
|
@@ -254,14 +260,19 @@ export class Base extends TypedEventEmitter {
|
|
|
254
260
|
this.once('client:close', onClose);
|
|
255
261
|
}
|
|
256
262
|
else {
|
|
257
|
-
if (attempt
|
|
258
|
-
|
|
259
|
-
return;
|
|
263
|
+
if (attempt > 0) {
|
|
264
|
+
error = new MultipleErrors(`${operationId} failed ${attempt + 1} times.`, errors);
|
|
260
265
|
}
|
|
261
|
-
|
|
266
|
+
this.emitWithDebug('client', 'performWithRetry:failed', operationId, retries, errors);
|
|
267
|
+
callback(error);
|
|
268
|
+
return;
|
|
262
269
|
}
|
|
263
270
|
return;
|
|
264
271
|
}
|
|
272
|
+
// Make sure all previous errors are deleted
|
|
273
|
+
if (errors.length > 0) {
|
|
274
|
+
errors.splice(0, errors.length);
|
|
275
|
+
}
|
|
265
276
|
callback(null, result);
|
|
266
277
|
});
|
|
267
278
|
return callback[kCallbackPromise];
|
|
@@ -398,6 +409,7 @@ export class Base extends TypedEventEmitter {
|
|
|
398
409
|
const unknownTopicError = error.findBy('apiCode', 3);
|
|
399
410
|
if (unknownTopicError) {
|
|
400
411
|
const topicIndexMatch = unknownTopicError.path?.match(/\/topics\/(\d+)/);
|
|
412
|
+
/* c8 ignore next 3 - Hard to test */
|
|
401
413
|
const topicIndex = topicIndexMatch ? parseInt(topicIndexMatch[1]) : -1;
|
|
402
414
|
const topicName = topicIndex >= 0 && topicIndex < topicsToFetch.length ? topicsToFetch[topicIndex] : 'unknown';
|
|
403
415
|
deduplicateCallback(new UserError(`Unknown topic ${topicName}.`));
|
|
@@ -405,6 +417,7 @@ export class Base extends TypedEventEmitter {
|
|
|
405
417
|
}
|
|
406
418
|
const hasStaleMetadata = error.findBy('hasStaleMetadata', true);
|
|
407
419
|
// Stale metadata, we need to fetch everything again
|
|
420
|
+
/* c8 ignore next 4 - Hard to test */
|
|
408
421
|
if (hasStaleMetadata) {
|
|
409
422
|
this.clearMetadata();
|
|
410
423
|
topicsToFetch = topics;
|
|
@@ -172,6 +172,7 @@ export class Consumer extends Base {
|
|
|
172
172
|
}
|
|
173
173
|
options.autocommit ??= this[kOptions].autocommit ?? true;
|
|
174
174
|
options.maxBytes ??= this[kOptions].maxBytes;
|
|
175
|
+
options.maxBytesPerPartition ??= this[kOptions].maxBytesPerPartition ?? options.maxBytes;
|
|
175
176
|
options.highWaterMark ??= this[kOptions].highWaterMark;
|
|
176
177
|
options.registry ??= this[kOptions].registry;
|
|
177
178
|
options.beforeDeserialization ??= this[kOptions].beforeDeserialization;
|
|
@@ -483,7 +484,7 @@ export class Consumer extends Base {
|
|
|
483
484
|
callback(error, response);
|
|
484
485
|
}, 0);
|
|
485
486
|
}
|
|
486
|
-
#commit(options, callback) {
|
|
487
|
+
#commit(options, callback, rejoinAttempts = 0) {
|
|
487
488
|
this.#performGroupOperation('commit', (connection, groupCallback) => {
|
|
488
489
|
const topics = new Map();
|
|
489
490
|
for (const { topic, partition, offset, leaderEpoch } of options.offsets) {
|
|
@@ -507,6 +508,16 @@ export class Consumer extends Base {
|
|
|
507
508
|
api(connection, this.groupId, this.#useConsumerGroupProtocol ? this.#memberEpoch : this.generationId, this.memberId, null, Array.from(topics.values()), groupCallback);
|
|
508
509
|
});
|
|
509
510
|
}, error => {
|
|
511
|
+
if (error && rejoinAttempts < this[kOptions].retries && this.#getRejoinError(error)) {
|
|
512
|
+
this.joinGroup({}, joinError => {
|
|
513
|
+
if (joinError) {
|
|
514
|
+
callback(joinError);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
this.#commit(options, callback, rejoinAttempts + 1);
|
|
518
|
+
});
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
510
521
|
callback(error);
|
|
511
522
|
});
|
|
512
523
|
}
|
|
@@ -608,7 +619,7 @@ export class Consumer extends Base {
|
|
|
608
619
|
});
|
|
609
620
|
});
|
|
610
621
|
}
|
|
611
|
-
#listCommittedOffsets(options, callback) {
|
|
622
|
+
#listCommittedOffsets(options, callback, staleMemberEpochRetries = 0) {
|
|
612
623
|
const topics = [];
|
|
613
624
|
for (const { topic: name, partitions } of options.topics) {
|
|
614
625
|
topics.push({ name, partitionIndexes: partitions });
|
|
@@ -630,6 +641,18 @@ export class Consumer extends Base {
|
|
|
630
641
|
});
|
|
631
642
|
}, (error, response) => {
|
|
632
643
|
if (error) {
|
|
644
|
+
if (this.#useConsumerGroupProtocol &&
|
|
645
|
+
staleMemberEpochRetries < this[kOptions].retries &&
|
|
646
|
+
error.findBy?.('apiId', 'STALE_MEMBER_EPOCH')) {
|
|
647
|
+
this.#consumerGroupHeartbeat(this[kOptions], heartbeatError => {
|
|
648
|
+
if (heartbeatError) {
|
|
649
|
+
callback(this.#handleMetadataError(heartbeatError));
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
this.#listCommittedOffsets(options, callback, staleMemberEpochRetries + 1);
|
|
653
|
+
});
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
633
656
|
callback(this.#handleMetadataError(error));
|
|
634
657
|
return;
|
|
635
658
|
}
|
|
@@ -19,6 +19,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
19
19
|
get offsetsToCommit(): Map<string, CommitOptionsPartition>;
|
|
20
20
|
get offsetsCommitted(): Map<string, bigint>;
|
|
21
21
|
get committedOffsets(): Map<string, bigint>;
|
|
22
|
+
get connections(): ConnectionPool;
|
|
22
23
|
close(callback: CallbackWithPromise<void>): void;
|
|
23
24
|
close(): Promise<void>;
|
|
24
25
|
isActive(): boolean;
|
|
@@ -61,6 +61,8 @@ export class MessagesStream extends Readable {
|
|
|
61
61
|
#metricsConsumedMessages;
|
|
62
62
|
#corruptedMessageHandler;
|
|
63
63
|
#context;
|
|
64
|
+
#onConsumerGroupJoin;
|
|
65
|
+
#onBrokerDisconnect;
|
|
64
66
|
#pushRecordsOperation;
|
|
65
67
|
[kInstance];
|
|
66
68
|
/*
|
|
@@ -122,6 +124,14 @@ export class MessagesStream extends Readable {
|
|
|
122
124
|
this.#closeCallbacks = [];
|
|
123
125
|
this.#corruptedMessageHandler = onCorruptedMessage ?? defaultCorruptedMessageHandler;
|
|
124
126
|
this.#context = context;
|
|
127
|
+
this.#onConsumerGroupJoin = () => {
|
|
128
|
+
this.#offsetsCommitted.clear();
|
|
129
|
+
this.#partitionsEpochs.clear();
|
|
130
|
+
this.#scheduleRefreshOffsetsAndFetch();
|
|
131
|
+
};
|
|
132
|
+
this.#onBrokerDisconnect = () => {
|
|
133
|
+
this.#partitionsEpochs.clear();
|
|
134
|
+
};
|
|
125
135
|
if (registry) {
|
|
126
136
|
this.#pushRecordsOperation = this.#beforeDeserialization.bind(this, registry.getBeforeDeserializationHook());
|
|
127
137
|
}
|
|
@@ -150,18 +160,12 @@ export class MessagesStream extends Readable {
|
|
|
150
160
|
// When the consumer joins a group, we need to fetch again as the assignments
|
|
151
161
|
// will have changed so we may have gone from last with no assignments to
|
|
152
162
|
// having some.
|
|
153
|
-
this.#consumer.on('consumer:group:join',
|
|
154
|
-
this.#offsetsCommitted.clear();
|
|
155
|
-
this.#partitionsEpochs.clear();
|
|
156
|
-
this.#scheduleRefreshOffsetsAndFetch();
|
|
157
|
-
});
|
|
163
|
+
this.#consumer.on('consumer:group:join', this.#onConsumerGroupJoin);
|
|
158
164
|
if (consumer[kPrometheus]) {
|
|
159
165
|
this.#metricsConsumedMessages = ensureMetric(consumer[kPrometheus], 'Counter', 'kafka_consumed_messages', 'Number of consumed Kafka messages');
|
|
160
166
|
}
|
|
161
167
|
// Whenever the consumer loses a connection, reset all the partitions epochs
|
|
162
|
-
consumer.on('client:broker:disconnect',
|
|
163
|
-
this.#partitionsEpochs.clear();
|
|
164
|
-
});
|
|
168
|
+
consumer.on('client:broker:disconnect', this.#onBrokerDisconnect);
|
|
165
169
|
notifyCreation('messages-stream', this);
|
|
166
170
|
}
|
|
167
171
|
/* c8 ignore next 3 - Simple getter */
|
|
@@ -188,6 +192,10 @@ export class MessagesStream extends Readable {
|
|
|
188
192
|
get committedOffsets() {
|
|
189
193
|
return this.#offsetsCommitted;
|
|
190
194
|
}
|
|
195
|
+
/* c8 ignore next 3 - Simple getter */
|
|
196
|
+
get connections() {
|
|
197
|
+
return this[kConnections];
|
|
198
|
+
}
|
|
191
199
|
close(callback) {
|
|
192
200
|
if (!callback) {
|
|
193
201
|
callback = createPromisifiedCallback();
|
|
@@ -298,12 +306,23 @@ export class MessagesStream extends Readable {
|
|
|
298
306
|
return super[Symbol.asyncIterator]();
|
|
299
307
|
}
|
|
300
308
|
_construct(callback) {
|
|
301
|
-
this.#
|
|
309
|
+
this.#refreshOffsetsInflight = true;
|
|
310
|
+
this.#refreshOffsets(error => {
|
|
311
|
+
const wasPending = this.#refreshOffsetsPending;
|
|
312
|
+
this.#refreshOffsetsInflight = false;
|
|
313
|
+
this.#refreshOffsetsPending = false;
|
|
314
|
+
if (!error && wasPending) {
|
|
315
|
+
this.#scheduleRefreshOffsetsAndFetch();
|
|
316
|
+
}
|
|
317
|
+
callback(error ?? undefined);
|
|
318
|
+
});
|
|
302
319
|
}
|
|
303
320
|
_destroy(error, callback) {
|
|
304
321
|
if (this.#autocommitInterval) {
|
|
305
322
|
clearInterval(this.#autocommitInterval);
|
|
306
323
|
}
|
|
324
|
+
this.#consumer.removeListener('consumer:group:join', this.#onConsumerGroupJoin);
|
|
325
|
+
this.#consumer.removeListener('client:broker:disconnect', this.#onBrokerDisconnect);
|
|
307
326
|
this[kConnections].close(closeError => {
|
|
308
327
|
callback(closeError ?? error);
|
|
309
328
|
});
|
|
@@ -379,7 +398,7 @@ export class MessagesStream extends Readable {
|
|
|
379
398
|
{
|
|
380
399
|
partition,
|
|
381
400
|
fetchOffset,
|
|
382
|
-
partitionMaxBytes: this.#options.
|
|
401
|
+
partitionMaxBytes: this.#options.maxBytesPerPartition,
|
|
383
402
|
currentLeaderEpoch: leaderEpoch,
|
|
384
403
|
lastFetchedEpoch: leaderEpoch
|
|
385
404
|
}
|
|
@@ -589,7 +608,12 @@ export class MessagesStream extends Readable {
|
|
|
589
608
|
this.#autocommitInflight = false;
|
|
590
609
|
if (error) {
|
|
591
610
|
this.emit('autocommit', error);
|
|
592
|
-
|
|
611
|
+
// Only destroy the stream when the broker requires a group rejoin
|
|
612
|
+
// (ILLEGAL_GENERATION, UNKNOWN_MEMBER_ID, REBALANCE_IN_PROGRESS).
|
|
613
|
+
// Transient coordinator errors must not tear down the consumption loop.
|
|
614
|
+
if (error.findBy?.('needsRejoin', true)) {
|
|
615
|
+
this.destroy(error);
|
|
616
|
+
}
|
|
593
617
|
return;
|
|
594
618
|
}
|
|
595
619
|
for (const { topic, partition, offset } of offsets) {
|
|
@@ -635,7 +659,10 @@ export class MessagesStream extends Readable {
|
|
|
635
659
|
topics.push(assignment);
|
|
636
660
|
}
|
|
637
661
|
if (!topics.length) {
|
|
638
|
-
|
|
662
|
+
// No assignment yet: do not seed fallback offsets for the whole topic.
|
|
663
|
+
// consumer:group:join will refresh once partitions are assigned.
|
|
664
|
+
this.emit('offsets');
|
|
665
|
+
callback(null);
|
|
639
666
|
return;
|
|
640
667
|
}
|
|
641
668
|
this.#consumer.listCommittedOffsets({ topics }, (error, commits) => {
|
|
@@ -662,6 +689,7 @@ export class MessagesStream extends Readable {
|
|
|
662
689
|
this.#refreshOffsetsInflight = true;
|
|
663
690
|
this.#refreshOffsets(error => {
|
|
664
691
|
const shouldDestroyOnError = this.#refreshOffsetsDestroyOnError;
|
|
692
|
+
const wasPending = this.#refreshOffsetsPending;
|
|
665
693
|
this.#refreshOffsetsInflight = false;
|
|
666
694
|
this.#refreshOffsetsDestroyOnError = false;
|
|
667
695
|
this.#refreshOffsetsPending = false;
|
|
@@ -673,8 +701,7 @@ export class MessagesStream extends Readable {
|
|
|
673
701
|
return;
|
|
674
702
|
}
|
|
675
703
|
// A new one was scheduled while the previous one was inflight, we need to run it immediately
|
|
676
|
-
|
|
677
|
-
if (this.#refreshOffsetsPending) {
|
|
704
|
+
if (wasPending) {
|
|
678
705
|
this.#scheduleRefreshOffsetsAndFetch(shouldDestroyOnError);
|
|
679
706
|
return;
|
|
680
707
|
}
|
|
@@ -97,6 +97,10 @@ export declare const consumeOptionsProperties: {
|
|
|
97
97
|
type: string;
|
|
98
98
|
minimum: number;
|
|
99
99
|
};
|
|
100
|
+
maxBytesPerPartition: {
|
|
101
|
+
type: string;
|
|
102
|
+
minimum: number;
|
|
103
|
+
};
|
|
100
104
|
maxWaitTime: {
|
|
101
105
|
type: string;
|
|
102
106
|
minimum: number;
|
|
@@ -217,6 +221,10 @@ export declare const consumeOptionsSchema: {
|
|
|
217
221
|
type: string;
|
|
218
222
|
minimum: number;
|
|
219
223
|
};
|
|
224
|
+
maxBytesPerPartition: {
|
|
225
|
+
type: string;
|
|
226
|
+
minimum: number;
|
|
227
|
+
};
|
|
220
228
|
maxWaitTime: {
|
|
221
229
|
type: string;
|
|
222
230
|
minimum: number;
|
|
@@ -379,6 +387,10 @@ export declare const consumerOptionsSchema: {
|
|
|
379
387
|
type: string;
|
|
380
388
|
minimum: number;
|
|
381
389
|
};
|
|
390
|
+
maxBytesPerPartition: {
|
|
391
|
+
type: string;
|
|
392
|
+
minimum: number;
|
|
393
|
+
};
|
|
382
394
|
maxWaitTime: {
|
|
383
395
|
type: string;
|
|
384
396
|
minimum: number;
|
|
@@ -502,6 +514,10 @@ export declare const fetchOptionsSchema: {
|
|
|
502
514
|
type: string;
|
|
503
515
|
minimum: number;
|
|
504
516
|
};
|
|
517
|
+
maxBytesPerPartition: {
|
|
518
|
+
type: string;
|
|
519
|
+
minimum: number;
|
|
520
|
+
};
|
|
505
521
|
maxWaitTime: {
|
|
506
522
|
type: string;
|
|
507
523
|
minimum: number;
|
|
@@ -58,6 +58,7 @@ export const consumeOptionsProperties = {
|
|
|
58
58
|
autocommit: { oneOf: [{ type: 'boolean' }, { type: 'number', minimum: 100 }] },
|
|
59
59
|
minBytes: { type: 'number', minimum: 0 },
|
|
60
60
|
maxBytes: { type: 'number', minimum: 0 },
|
|
61
|
+
maxBytesPerPartition: { type: 'number', minimum: 0 },
|
|
61
62
|
maxWaitTime: { type: 'number', minimum: 0 },
|
|
62
63
|
isolationLevel: { type: 'number', enum: allowedFetchIsolationLevels },
|
|
63
64
|
deserializers: serdeProperties,
|
|
@@ -65,6 +65,7 @@ export interface ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue> {
|
|
|
65
65
|
autocommit?: boolean | number;
|
|
66
66
|
minBytes?: number;
|
|
67
67
|
maxBytes?: number;
|
|
68
|
+
maxBytesPerPartition?: number;
|
|
68
69
|
maxWaitTime?: number;
|
|
69
70
|
isolationLevel?: number;
|
|
70
71
|
deserializers?: Partial<Deserializers<Key, Value, HeaderKey, HeaderValue>>;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { murmur2 } from "../../protocol/murmur2.js";
|
|
2
2
|
const compatibilityMurmur2Mask = 0x7fffffff;
|
|
3
3
|
export function defaultPartitioner(_, key) {
|
|
4
|
+
/* c8 ignore next - Hard to test */
|
|
4
5
|
return Buffer.isBuffer(key) ? murmur2(key) >>> 0 : 0;
|
|
5
6
|
}
|
|
6
7
|
export function compatibilityPartitioner(_, key) {
|
|
8
|
+
/* c8 ignore next - Hard to test */
|
|
7
9
|
return Buffer.isBuffer(key) ? murmur2(key) & compatibilityMurmur2Mask : 0;
|
|
8
10
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CallbackWithPromise } from '../../apis/callbacks.ts';
|
|
2
|
+
import { type Broker, type Connection } from '../../network/connection.ts';
|
|
2
3
|
import { type Message } from '../../protocol/records.ts';
|
|
3
4
|
import { kTransaction, kTransactionAddOffsets, kTransactionAddPartitions, kTransactionCancel, kTransactionCommitOffset, kTransactionEnd, kTransactionFindCoordinator } from '../../symbols.ts';
|
|
4
5
|
import { Base } from '../base/base.ts';
|
|
@@ -27,6 +28,11 @@ export declare class Producer<Key = Buffer, Value = Buffer, HeaderKey = Buffer,
|
|
|
27
28
|
asStream(options?: ProducerStreamOptions<Key, Value, HeaderKey, HeaderValue>): ProducerStream<Key, Value, HeaderKey, HeaderValue>;
|
|
28
29
|
beginTransaction(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Transaction<Key, Value, HeaderKey, HeaderValue>>): void;
|
|
29
30
|
beginTransaction(options?: ProduceOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Transaction<Key, Value, HeaderKey, HeaderValue>>;
|
|
31
|
+
getSendTopicPartitions(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Map<string, Set<number>>;
|
|
32
|
+
getSendBrokers(options: SendOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Record<string, Broker>>): void;
|
|
33
|
+
getSendBrokers(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Record<string, Broker>>;
|
|
34
|
+
getSendConnections(options: SendOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Record<string, Connection>>): void;
|
|
35
|
+
getSendConnections(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Record<string, Connection>>;
|
|
30
36
|
[kTransactionFindCoordinator](callback: CallbackWithPromise<void>): void;
|
|
31
37
|
[kTransactionAddPartitions](transactionId: number, topicsPartitions: Map<string, Set<number>>, callback: CallbackWithPromise<void>): void;
|
|
32
38
|
[kTransactionAddOffsets](transactionId: number, groupId: string, callback: CallbackWithPromise<void>): void;
|
|
@@ -243,6 +243,98 @@ export class Producer extends Base {
|
|
|
243
243
|
producerTransactionsChannel.traceCallback(this.#transaction[kTransactionPrepare], 2, createDiagnosticContext({ client: this, operation: 'begin' }), this.#transaction, this.#producerInfo?.transactionalId, options, callback);
|
|
244
244
|
return callback[kCallbackPromise];
|
|
245
245
|
}
|
|
246
|
+
getSendTopicPartitions(options) {
|
|
247
|
+
const topicsPartitions = new Map();
|
|
248
|
+
const partitioner = options.partitioner ?? this[kOptions].partitioner;
|
|
249
|
+
for (const message of options.messages) {
|
|
250
|
+
const topic = message.topic;
|
|
251
|
+
let key;
|
|
252
|
+
let headers = new Map();
|
|
253
|
+
try {
|
|
254
|
+
if (message.headers) {
|
|
255
|
+
headers =
|
|
256
|
+
message.headers instanceof Map
|
|
257
|
+
? message.headers
|
|
258
|
+
: new Map(Object.entries(message.headers));
|
|
259
|
+
}
|
|
260
|
+
key = this.#keySerializer(message.key, headers, message);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
throw new UserError('Failed to serialize a message.', { cause: error });
|
|
264
|
+
}
|
|
265
|
+
const partition = this.#assignPartition(message, partitioner, key, topic);
|
|
266
|
+
let partitions = topicsPartitions.get(topic);
|
|
267
|
+
if (!partitions) {
|
|
268
|
+
partitions = new Set();
|
|
269
|
+
topicsPartitions.set(topic, partitions);
|
|
270
|
+
}
|
|
271
|
+
partitions.add(partition);
|
|
272
|
+
}
|
|
273
|
+
return topicsPartitions;
|
|
274
|
+
}
|
|
275
|
+
getSendBrokers(options, callback) {
|
|
276
|
+
if (!callback) {
|
|
277
|
+
callback = createPromisifiedCallback();
|
|
278
|
+
}
|
|
279
|
+
if (this[kCheckNotClosed](callback)) {
|
|
280
|
+
return callback[kCallbackPromise];
|
|
281
|
+
}
|
|
282
|
+
let topicsPartitions;
|
|
283
|
+
try {
|
|
284
|
+
topicsPartitions = this.getSendTopicPartitions(options);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
callback(error);
|
|
288
|
+
return callback[kCallbackPromise];
|
|
289
|
+
}
|
|
290
|
+
this[kMetadata]({ topics: Array.from(topicsPartitions.keys()), autocreateTopics: options.autocreateTopics }, (error, metadata) => {
|
|
291
|
+
if (error) {
|
|
292
|
+
callback(error);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const brokers = {};
|
|
296
|
+
for (const [topic, partitions] of topicsPartitions) {
|
|
297
|
+
for (const rawPartition of partitions) {
|
|
298
|
+
const partition = rawPartition & metadata.topics.get(topic).partitionsCount;
|
|
299
|
+
const leader = metadata.topics.get(topic).partitions[partition].leader;
|
|
300
|
+
const broker = metadata.brokers.get(leader);
|
|
301
|
+
brokers[`${topic}:${partition}`] = broker;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
callback(null, brokers);
|
|
305
|
+
});
|
|
306
|
+
return callback[kCallbackPromise];
|
|
307
|
+
}
|
|
308
|
+
getSendConnections(options, callback) {
|
|
309
|
+
if (!callback) {
|
|
310
|
+
callback = createPromisifiedCallback();
|
|
311
|
+
}
|
|
312
|
+
if (this[kCheckNotClosed](callback)) {
|
|
313
|
+
return callback[kCallbackPromise];
|
|
314
|
+
}
|
|
315
|
+
this.getSendBrokers(options, (error, brokers) => {
|
|
316
|
+
if (error) {
|
|
317
|
+
callback(error);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
runConcurrentCallbacks('Preparing producer connections failed.', Object.entries(brokers), ([topicPartition, broker], concurrentCallback) => {
|
|
321
|
+
this[kGetConnection](broker, (error, connection) => {
|
|
322
|
+
if (error) {
|
|
323
|
+
concurrentCallback(error);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
concurrentCallback(null, [topicPartition, connection]);
|
|
327
|
+
});
|
|
328
|
+
}, (error, results) => {
|
|
329
|
+
if (error) {
|
|
330
|
+
callback(error);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
callback(null, Object.fromEntries(results));
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
return callback[kCallbackPromise];
|
|
337
|
+
}
|
|
246
338
|
[kTransactionFindCoordinator](callback) {
|
|
247
339
|
if (this.#coordinatorId !== undefined) {
|
|
248
340
|
callback(null);
|
|
@@ -533,22 +625,7 @@ export class Producer extends Base {
|
|
|
533
625
|
callback(new UserError('Failed to serialize a message.', { cause: error }));
|
|
534
626
|
return;
|
|
535
627
|
}
|
|
536
|
-
|
|
537
|
-
if (typeof message.partition !== 'number') {
|
|
538
|
-
if (partitioner) {
|
|
539
|
-
partition = partitioner(message, key);
|
|
540
|
-
}
|
|
541
|
-
else if (key) {
|
|
542
|
-
partition = defaultPartitioner(message, key);
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
// Use the roundrobin
|
|
546
|
-
partition = this.#partitionsRoundRobin.postIncrement(topic, 1, 0);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
550
|
-
partition = message.partition;
|
|
551
|
-
}
|
|
628
|
+
const partition = this.#assignPartition(message, partitioner, key, topic);
|
|
552
629
|
topics.add(topic);
|
|
553
630
|
messages.push({
|
|
554
631
|
key,
|
|
@@ -610,16 +687,12 @@ export class Producer extends Base {
|
|
|
610
687
|
nodes.push(destination);
|
|
611
688
|
this.#performSingleDestinationSend(topics, destinationMessages, this[kOptions].timeout, sendOptions.acks, sendOptions.autocreateTopics, sendOptions.repeatOnStaleMetadata, produceOptions, concurrentCallback);
|
|
612
689
|
}, (error, apiResults) => {
|
|
613
|
-
if (error) {
|
|
614
|
-
callback(error);
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
690
|
this.#metricsProducedMessages?.inc(messages.length);
|
|
618
691
|
const results = {};
|
|
619
692
|
if (sendOptions.acks === ProduceAcks.NO_RESPONSE) {
|
|
620
693
|
const unwritableNodes = [];
|
|
621
694
|
for (let i = 0; i < apiResults.length; i++) {
|
|
622
|
-
if (apiResults[i] === false) {
|
|
695
|
+
if (typeof apiResults[i] === 'undefined' || apiResults[i] === false) {
|
|
623
696
|
unwritableNodes.push(nodes[i]);
|
|
624
697
|
}
|
|
625
698
|
}
|
|
@@ -628,7 +701,7 @@ export class Producer extends Base {
|
|
|
628
701
|
else {
|
|
629
702
|
const topics = [];
|
|
630
703
|
for (const result of apiResults) {
|
|
631
|
-
for (const { name, partitionResponses } of result
|
|
704
|
+
for (const { name, partitionResponses } of result?.responses ?? []) {
|
|
632
705
|
for (const partitionResponse of partitionResponses) {
|
|
633
706
|
topics.push({
|
|
634
707
|
topic: name,
|
|
@@ -642,7 +715,14 @@ export class Producer extends Base {
|
|
|
642
715
|
results.offsets = topics;
|
|
643
716
|
}
|
|
644
717
|
}
|
|
645
|
-
|
|
718
|
+
if (error) {
|
|
719
|
+
;
|
|
720
|
+
error.produced = results;
|
|
721
|
+
callback(error);
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
callback(null, results);
|
|
725
|
+
}
|
|
646
726
|
});
|
|
647
727
|
});
|
|
648
728
|
}
|
|
@@ -673,6 +753,7 @@ export class Producer extends Base {
|
|
|
673
753
|
if (error) {
|
|
674
754
|
// If the last error was due to stale metadata, we retry the operation with this set of messages
|
|
675
755
|
// since the partition is already set, it should attempt on the new destination
|
|
756
|
+
/* c8 ignore next 3 - Hard to test */
|
|
676
757
|
const kafkaError = GenericError.isGenericError(error)
|
|
677
758
|
? error
|
|
678
759
|
: null;
|
|
@@ -682,11 +763,12 @@ export class Producer extends Base {
|
|
|
682
763
|
this.#performSingleDestinationSend(topics, messages, timeout, acks, autocreateTopics, false, produceOptions, callback);
|
|
683
764
|
return;
|
|
684
765
|
}
|
|
685
|
-
callback(error);
|
|
766
|
+
callback(error, results);
|
|
686
767
|
return;
|
|
687
768
|
}
|
|
688
769
|
callback(error, results);
|
|
689
770
|
}, 0, [], error => {
|
|
771
|
+
/* c8 ignore next 3 - Hard to test */
|
|
690
772
|
if (!repeatOnStaleMetadata || !GenericError.isGenericError(error)) {
|
|
691
773
|
return false;
|
|
692
774
|
}
|
|
@@ -752,4 +834,23 @@ export class Producer extends Base {
|
|
|
752
834
|
this.#send(options, callback);
|
|
753
835
|
});
|
|
754
836
|
}
|
|
837
|
+
#assignPartition(message, partitioner, key, topic) {
|
|
838
|
+
let partition = 0;
|
|
839
|
+
if (typeof message.partition !== 'number') {
|
|
840
|
+
if (partitioner) {
|
|
841
|
+
partition = partitioner(message, key, { metadata: this.currentMetadata });
|
|
842
|
+
}
|
|
843
|
+
else if (key) {
|
|
844
|
+
partition = defaultPartitioner(message, key);
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
// Use the roundrobin
|
|
848
|
+
partition = this.#partitionsRoundRobin.postIncrement(topic, 1, 0);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
partition = message.partition;
|
|
853
|
+
}
|
|
854
|
+
return partition;
|
|
855
|
+
}
|
|
755
856
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CompressionAlgorithmValue } from '../../protocol/compression.ts';
|
|
2
2
|
import { type MessageToProduce } from '../../protocol/records.ts';
|
|
3
3
|
import { type SchemaRegistry } from '../../registries/abstract.ts';
|
|
4
|
-
import { type BaseOptions, type TopicWithPartitionAndOffset } from '../base/types.ts';
|
|
4
|
+
import { type BaseOptions, type ClusterMetadata, type TopicWithPartitionAndOffset } from '../base/types.ts';
|
|
5
5
|
import { type BeforeSerializationHook, type Serializers } from '../serde.ts';
|
|
6
6
|
export interface ProducerInfo {
|
|
7
7
|
producerId: bigint;
|
|
@@ -12,7 +12,10 @@ export interface ProduceResult {
|
|
|
12
12
|
offsets?: TopicWithPartitionAndOffset[];
|
|
13
13
|
unwritableNodes?: number[];
|
|
14
14
|
}
|
|
15
|
-
export
|
|
15
|
+
export interface PartitionerContext {
|
|
16
|
+
metadata: ClusterMetadata | undefined;
|
|
17
|
+
}
|
|
18
|
+
export type Partitioner<Key, Value, HeaderKey, HeaderValue> = (message: MessageToProduce<Key, Value, HeaderKey, HeaderValue>, key: Buffer | undefined, context: PartitionerContext) => number;
|
|
16
19
|
export interface ProducerStreamReport {
|
|
17
20
|
batchId: number;
|
|
18
21
|
count: number;
|
package/dist/errors.js
CHANGED
|
@@ -120,7 +120,7 @@ export class ProtocolError extends GenericError {
|
|
|
120
120
|
'NOT_LEADER_OR_FOLLOWER',
|
|
121
121
|
'FENCED_LEADER_EPOCH'
|
|
122
122
|
].includes(id),
|
|
123
|
-
needsRejoin: ['MEMBER_ID_REQUIRED', 'UNKNOWN_MEMBER_ID', 'REBALANCE_IN_PROGRESS'].includes(id),
|
|
123
|
+
needsRejoin: ['MEMBER_ID_REQUIRED', 'UNKNOWN_MEMBER_ID', 'REBALANCE_IN_PROGRESS', 'ILLEGAL_GENERATION'].includes(id),
|
|
124
124
|
producerFenced: id === 'INVALID_PRODUCER_EPOCH',
|
|
125
125
|
rebalanceInProgress: id === 'REBALANCE_IN_PROGRESS',
|
|
126
126
|
unknownMemberId: id === 'UNKNOWN_MEMBER_ID',
|
|
@@ -27,12 +27,15 @@ export declare class ConnectionPool extends TypedEventEmitter<ConnectionPoolEven
|
|
|
27
27
|
get instanceId(): number;
|
|
28
28
|
get ownerId(): number | undefined;
|
|
29
29
|
get context(): unknown;
|
|
30
|
+
[Symbol.iterator](): MapIterator<[string, Connection]>;
|
|
30
31
|
get(broker: Broker, callback: CallbackWithPromise<Connection>): void;
|
|
31
32
|
get(broker: Broker): Promise<Connection>;
|
|
32
33
|
getFirstAvailable(brokers: Broker[], callback: CallbackWithPromise<Connection>): void;
|
|
33
34
|
getFirstAvailable(brokers: Broker[]): Promise<Connection>;
|
|
35
|
+
getEstablishedConnection(broker: Broker): Connection | undefined;
|
|
34
36
|
close(callback: CallbackWithPromise<void>): void;
|
|
35
37
|
close(): Promise<void>;
|
|
36
38
|
isActive(): boolean;
|
|
37
39
|
isConnected(): boolean;
|
|
40
|
+
has(broker: Broker): boolean;
|
|
38
41
|
}
|
|
@@ -34,6 +34,9 @@ export class ConnectionPool extends TypedEventEmitter {
|
|
|
34
34
|
get context() {
|
|
35
35
|
return this.#context;
|
|
36
36
|
}
|
|
37
|
+
[Symbol.iterator]() {
|
|
38
|
+
return this.#connections[Symbol.iterator]();
|
|
39
|
+
}
|
|
37
40
|
get(broker, callback) {
|
|
38
41
|
if (!callback) {
|
|
39
42
|
callback = createPromisifiedCallback();
|
|
@@ -48,6 +51,9 @@ export class ConnectionPool extends TypedEventEmitter {
|
|
|
48
51
|
connectionsPoolGetsChannel.traceCallback(this.#getFirstAvailable, 3, createDiagnosticContext({ connectionPool: this, brokers, operation: 'getFirstAvailable' }), this, brokers, 0, [], callback);
|
|
49
52
|
return callback[kCallbackPromise];
|
|
50
53
|
}
|
|
54
|
+
getEstablishedConnection(broker) {
|
|
55
|
+
return this.#connections.get(`${broker.host}:${broker.port}`);
|
|
56
|
+
}
|
|
51
57
|
close(callback) {
|
|
52
58
|
if (!callback) {
|
|
53
59
|
callback = createPromisifiedCallback();
|
|
@@ -81,6 +87,9 @@ export class ConnectionPool extends TypedEventEmitter {
|
|
|
81
87
|
}
|
|
82
88
|
return true;
|
|
83
89
|
}
|
|
90
|
+
has(broker) {
|
|
91
|
+
return this.#connections.has(`${broker.host}:${broker.port}`);
|
|
92
|
+
}
|
|
84
93
|
#get(broker, callback) {
|
|
85
94
|
if (this.#closed) {
|
|
86
95
|
callback(new Error('Connection pool is closed.'));
|
|
@@ -122,6 +122,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
122
122
|
connectionOptions.servername =
|
|
123
123
|
typeof this.#options.tlsServerName === 'string' ? this.#options.tlsServerName : host;
|
|
124
124
|
}
|
|
125
|
+
/* c8 ignore next 13 - Hard to test */
|
|
125
126
|
const connectingSocketTimeoutHandler = () => {
|
|
126
127
|
const error = new TimeoutError(`Connection to ${host}:${port} timed out.`);
|
|
127
128
|
diagnosticContext.error = error;
|
|
@@ -5,7 +5,7 @@ import { type CallbackWithPromise } from "../../apis/callbacks";
|
|
|
5
5
|
import { type Callback } from "../../apis/definitions";
|
|
6
6
|
import { type Acl } from "../../apis/types";
|
|
7
7
|
import { Base } from "../base/base";
|
|
8
|
-
import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type
|
|
8
|
+
import { type AdminListOffsetsOptions, type AdminOptions, type AlterClientQuotasOptions, type AlterConfigsOptions, type AlterConsumerGroupOffsetsOptions, type BrokerLogDirDescription, type ConfigDescription, type CreateAclsOptions, type CreatedTopic, type CreatePartitionsOptions, type CreateTopicsOptions, type DeleteAclsOptions, type DeleteConsumerGroupOffsetsOptions, type DeletedRecordsTopic, type DeleteGroupsOptions, type DeleteRecordsOptions, type DeleteTopicsOptions, type DescribeAclsOptions, type DescribeClientQuotasOptions, type DescribeConfigsOptions, type DescribeGroupsOptions, type DescribeLogDirsOptions, type FindCoordinatorOptions, type FindCoordinatorResult, type Group, type GroupBase, type IncrementalAlterConfigsOptions, type ListConsumerGroupOffsetsGroup, type ListConsumerGroupOffsetsOptions, type ListedOffsetsTopic, type ListGroupsOptions, type ListTopicsOptions, type RemoveMembersFromConsumerGroupOptions } from "./types";
|
|
9
9
|
export declare class Admin extends Base<AdminOptions> {
|
|
10
10
|
#private;
|
|
11
11
|
constructor(options: AdminOptions);
|
|
@@ -66,6 +66,8 @@ export declare class Base<OptionsType extends BaseOptions = BaseOptions, EventsT
|
|
|
66
66
|
get closed(): boolean;
|
|
67
67
|
get type(): ClientType;
|
|
68
68
|
get context(): unknown;
|
|
69
|
+
get currentMetadata(): ClusterMetadata | undefined;
|
|
70
|
+
get connections(): ConnectionPool;
|
|
69
71
|
emitWithDebug(section: string | null, name: string, ...args: any[]): boolean;
|
|
70
72
|
close(callback: CallbackWithPromise<void>): void;
|
|
71
73
|
close(): Promise<void>;
|
|
@@ -19,6 +19,7 @@ export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends
|
|
|
19
19
|
get offsetsToCommit(): Map<string, CommitOptionsPartition>;
|
|
20
20
|
get offsetsCommitted(): Map<string, bigint>;
|
|
21
21
|
get committedOffsets(): Map<string, bigint>;
|
|
22
|
+
get connections(): ConnectionPool;
|
|
22
23
|
close(callback: CallbackWithPromise<void>): void;
|
|
23
24
|
close(): Promise<void>;
|
|
24
25
|
isActive(): boolean;
|
|
@@ -97,6 +97,10 @@ export declare const consumeOptionsProperties: {
|
|
|
97
97
|
type: string;
|
|
98
98
|
minimum: number;
|
|
99
99
|
};
|
|
100
|
+
maxBytesPerPartition: {
|
|
101
|
+
type: string;
|
|
102
|
+
minimum: number;
|
|
103
|
+
};
|
|
100
104
|
maxWaitTime: {
|
|
101
105
|
type: string;
|
|
102
106
|
minimum: number;
|
|
@@ -217,6 +221,10 @@ export declare const consumeOptionsSchema: {
|
|
|
217
221
|
type: string;
|
|
218
222
|
minimum: number;
|
|
219
223
|
};
|
|
224
|
+
maxBytesPerPartition: {
|
|
225
|
+
type: string;
|
|
226
|
+
minimum: number;
|
|
227
|
+
};
|
|
220
228
|
maxWaitTime: {
|
|
221
229
|
type: string;
|
|
222
230
|
minimum: number;
|
|
@@ -379,6 +387,10 @@ export declare const consumerOptionsSchema: {
|
|
|
379
387
|
type: string;
|
|
380
388
|
minimum: number;
|
|
381
389
|
};
|
|
390
|
+
maxBytesPerPartition: {
|
|
391
|
+
type: string;
|
|
392
|
+
minimum: number;
|
|
393
|
+
};
|
|
382
394
|
maxWaitTime: {
|
|
383
395
|
type: string;
|
|
384
396
|
minimum: number;
|
|
@@ -502,6 +514,10 @@ export declare const fetchOptionsSchema: {
|
|
|
502
514
|
type: string;
|
|
503
515
|
minimum: number;
|
|
504
516
|
};
|
|
517
|
+
maxBytesPerPartition: {
|
|
518
|
+
type: string;
|
|
519
|
+
minimum: number;
|
|
520
|
+
};
|
|
505
521
|
maxWaitTime: {
|
|
506
522
|
type: string;
|
|
507
523
|
minimum: number;
|
|
@@ -65,6 +65,7 @@ export interface ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue> {
|
|
|
65
65
|
autocommit?: boolean | number;
|
|
66
66
|
minBytes?: number;
|
|
67
67
|
maxBytes?: number;
|
|
68
|
+
maxBytesPerPartition?: number;
|
|
68
69
|
maxWaitTime?: number;
|
|
69
70
|
isolationLevel?: number;
|
|
70
71
|
deserializers?: Partial<Deserializers<Key, Value, HeaderKey, HeaderValue>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CallbackWithPromise } from "../../apis/callbacks";
|
|
2
|
+
import { type Broker, type Connection } from "../../network/connection";
|
|
2
3
|
import { type Message } from "../../protocol/records";
|
|
3
4
|
import { kTransaction, kTransactionAddOffsets, kTransactionAddPartitions, kTransactionCancel, kTransactionCommitOffset, kTransactionEnd, kTransactionFindCoordinator } from "../../symbols";
|
|
4
5
|
import { Base } from "../base/base";
|
|
@@ -27,6 +28,11 @@ export declare class Producer<Key = Buffer, Value = Buffer, HeaderKey = Buffer,
|
|
|
27
28
|
asStream(options?: ProducerStreamOptions<Key, Value, HeaderKey, HeaderValue>): ProducerStream<Key, Value, HeaderKey, HeaderValue>;
|
|
28
29
|
beginTransaction(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Transaction<Key, Value, HeaderKey, HeaderValue>>): void;
|
|
29
30
|
beginTransaction(options?: ProduceOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Transaction<Key, Value, HeaderKey, HeaderValue>>;
|
|
31
|
+
getSendTopicPartitions(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Map<string, Set<number>>;
|
|
32
|
+
getSendBrokers(options: SendOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Record<string, Broker>>): void;
|
|
33
|
+
getSendBrokers(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Record<string, Broker>>;
|
|
34
|
+
getSendConnections(options: SendOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<Record<string, Connection>>): void;
|
|
35
|
+
getSendConnections(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Promise<Record<string, Connection>>;
|
|
30
36
|
[kTransactionFindCoordinator](callback: CallbackWithPromise<void>): void;
|
|
31
37
|
[kTransactionAddPartitions](transactionId: number, topicsPartitions: Map<string, Set<number>>, callback: CallbackWithPromise<void>): void;
|
|
32
38
|
[kTransactionAddOffsets](transactionId: number, groupId: string, callback: CallbackWithPromise<void>): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CompressionAlgorithmValue } from "../../protocol/compression";
|
|
2
2
|
import { type MessageToProduce } from "../../protocol/records";
|
|
3
3
|
import { type SchemaRegistry } from "../../registries/abstract";
|
|
4
|
-
import { type BaseOptions, type TopicWithPartitionAndOffset } from "../base/types";
|
|
4
|
+
import { type BaseOptions, type ClusterMetadata, type TopicWithPartitionAndOffset } from "../base/types";
|
|
5
5
|
import { type BeforeSerializationHook, type Serializers } from "../serde";
|
|
6
6
|
export interface ProducerInfo {
|
|
7
7
|
producerId: bigint;
|
|
@@ -12,7 +12,10 @@ export interface ProduceResult {
|
|
|
12
12
|
offsets?: TopicWithPartitionAndOffset[];
|
|
13
13
|
unwritableNodes?: number[];
|
|
14
14
|
}
|
|
15
|
-
export
|
|
15
|
+
export interface PartitionerContext {
|
|
16
|
+
metadata: ClusterMetadata | undefined;
|
|
17
|
+
}
|
|
18
|
+
export type Partitioner<Key, Value, HeaderKey, HeaderValue> = (message: MessageToProduce<Key, Value, HeaderKey, HeaderValue>, key: Buffer | undefined, context: PartitionerContext) => number;
|
|
16
19
|
export interface ProducerStreamReport {
|
|
17
20
|
batchId: number;
|
|
18
21
|
count: number;
|
|
@@ -27,12 +27,15 @@ export declare class ConnectionPool extends TypedEventEmitter<ConnectionPoolEven
|
|
|
27
27
|
get instanceId(): number;
|
|
28
28
|
get ownerId(): number | undefined;
|
|
29
29
|
get context(): unknown;
|
|
30
|
+
[Symbol.iterator](): MapIterator<[string, Connection]>;
|
|
30
31
|
get(broker: Broker, callback: CallbackWithPromise<Connection>): void;
|
|
31
32
|
get(broker: Broker): Promise<Connection>;
|
|
32
33
|
getFirstAvailable(brokers: Broker[], callback: CallbackWithPromise<Connection>): void;
|
|
33
34
|
getFirstAvailable(brokers: Broker[]): Promise<Connection>;
|
|
35
|
+
getEstablishedConnection(broker: Broker): Connection | undefined;
|
|
34
36
|
close(callback: CallbackWithPromise<void>): void;
|
|
35
37
|
close(): Promise<void>;
|
|
36
38
|
isActive(): boolean;
|
|
37
39
|
isConnected(): boolean;
|
|
40
|
+
has(broker: Broker): boolean;
|
|
38
41
|
}
|
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.35.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/kafka",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.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)",
|
|
@@ -24,6 +24,24 @@
|
|
|
24
24
|
"type": "module",
|
|
25
25
|
"exports": "./dist/index.js",
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rm -rf dist && tsc -p tsconfig.base.json",
|
|
29
|
+
"postbuild": "./scripts/node scripts/postbuild.ts",
|
|
30
|
+
"lint": "eslint --cache",
|
|
31
|
+
"typecheck": "tsc -p . --noEmit",
|
|
32
|
+
"format": "prettier -w benchmarks playground src test",
|
|
33
|
+
"test": "c8 -c test/config/c8-local.json ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/*.test.ts' 'test/*/*.test.ts' 'test/*/*/*.test.ts'",
|
|
34
|
+
"test:ci": "c8 -c test/config/c8-ci.json ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/*.test.ts' 'test/*/*.test.ts' 'test/*/*/*.test.ts'",
|
|
35
|
+
"test:memory": "NODE_OPTIONS='--expose-gc' ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/**/*.memory-test.ts'",
|
|
36
|
+
"test:docker:up": "docker-compose up -d --wait",
|
|
37
|
+
"test:docker:down": "docker-compose down",
|
|
38
|
+
"ci": "npm run build && npm run lint && npm run test:ci",
|
|
39
|
+
"prepublishOnly": "npm run build && npm run lint",
|
|
40
|
+
"postpublish": "git push origin && git push origin -f --tags",
|
|
41
|
+
"generate:apis": "node scripts/generate-apis.ts",
|
|
42
|
+
"generate:errors": "node scripts/generate-errors.ts",
|
|
43
|
+
"create:api": "node scripts/create-api.ts"
|
|
44
|
+
},
|
|
27
45
|
"dependencies": {
|
|
28
46
|
"@platformatic/dynamic-buffer": "^0.3.1",
|
|
29
47
|
"@platformatic/wasm-utils": "^0.2.1",
|
|
@@ -84,21 +102,5 @@
|
|
|
84
102
|
"dist/typescript-4/*"
|
|
85
103
|
]
|
|
86
104
|
}
|
|
87
|
-
},
|
|
88
|
-
"scripts": {
|
|
89
|
-
"build": "rm -rf dist && tsc -p tsconfig.base.json",
|
|
90
|
-
"postbuild": "./scripts/node scripts/postbuild.ts",
|
|
91
|
-
"lint": "eslint --cache",
|
|
92
|
-
"typecheck": "tsc -p . --noEmit",
|
|
93
|
-
"format": "prettier -w benchmarks playground src test",
|
|
94
|
-
"test": "c8 -c test/config/c8-local.json ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/*.test.ts' 'test/*/*.test.ts' 'test/*/*/*.test.ts'",
|
|
95
|
-
"test:ci": "c8 -c test/config/c8-ci.json ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/*.test.ts' 'test/*/*.test.ts' 'test/*/*/*.test.ts'",
|
|
96
|
-
"test:memory": "NODE_OPTIONS='--expose-gc' ./scripts/node --test --test-reporter=cleaner-spec-reporter 'test/**/*.memory-test.ts'",
|
|
97
|
-
"test:docker:up": "docker-compose up -d --wait",
|
|
98
|
-
"test:docker:down": "docker-compose down",
|
|
99
|
-
"ci": "npm run build && npm run lint && npm run test:ci",
|
|
100
|
-
"generate:apis": "node scripts/generate-apis.ts",
|
|
101
|
-
"generate:errors": "node scripts/generate-errors.ts",
|
|
102
|
-
"create:api": "node scripts/create-api.ts"
|
|
103
105
|
}
|
|
104
106
|
}
|