@platformatic/kafka 0.4.2 → 1.1.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 CHANGED
@@ -264,6 +264,7 @@ Many of the methods accept the same options as the client's constructors. The co
264
264
  - [Admin API](./docs/admin.md)
265
265
  - [Base Client](./docs/base.md)
266
266
  - [Metrics](./docs/metrics.md)
267
+ - [Diagnostic and Instrumentation](./docs/diagnostic.md)
267
268
  - [Other APIs and Types](./docs/other.md)
268
269
 
269
270
  ## Requirements
@@ -1,7 +1,6 @@
1
1
  import { promisify } from 'node:util';
2
2
  export function createAPI(apiKey, apiVersion, createRequest, parseResponse, hasRequestHeaderTaggedFields = true, hasResponseHeaderTaggedFields = true) {
3
3
  const api = function api(connection, ...args) {
4
- /* c8 ignore next */
5
4
  const cb = typeof args[args.length - 1] === 'function' ? args.pop() : () => { };
6
5
  connection.send(apiKey, apiVersion, () => createRequest(...args), parseResponse, hasRequestHeaderTaggedFields, hasResponseHeaderTaggedFields, cb);
7
6
  };
@@ -5,13 +5,15 @@ import { api as describeGroupsV5 } from "../../apis/admin/describe-groups.js";
5
5
  import { api as listGroupsV5 } from "../../apis/admin/list-groups.js";
6
6
  import { FindCoordinatorKeyTypes } from "../../apis/enumerations.js";
7
7
  import { api as findCoordinatorV6 } from "../../apis/metadata/find-coordinator.js";
8
+ import { adminGroupsChannel, adminTopicsChannel, createDiagnosticContext } from "../../diagnostic.js";
8
9
  import { Reader } from "../../protocol/reader.js";
9
- import { Base, kBootstrapBrokers, kCheckNotClosed, kConnections, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "../base/base.js";
10
+ import { Base, kAfterCreate, kBootstrapBrokers, kCheckNotClosed, kConnections, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "../base/base.js";
10
11
  import { createPromisifiedCallback, kCallbackPromise, runConcurrentCallbacks } from "../callbacks.js";
11
12
  import { createTopicsOptionsValidator, deleteGroupsOptionsValidator, deleteTopicsOptionsValidator, describeGroupsOptionsValidator, listGroupsOptionsValidator } from "./options.js";
12
13
  export class Admin extends Base {
13
14
  constructor(options) {
14
15
  super(options);
16
+ this[kAfterCreate]('admin');
15
17
  }
16
18
  createTopics(options, callback) {
17
19
  if (!callback) {
@@ -25,7 +27,7 @@ export class Admin extends Base {
25
27
  callback(validationError, undefined);
26
28
  return callback[kCallbackPromise];
27
29
  }
28
- this.#createTopics(options, callback);
30
+ adminTopicsChannel.traceCallback(this.#createTopics, 1, createDiagnosticContext({ client: this, operation: 'createTopics', options }), this, options, callback);
29
31
  return callback[kCallbackPromise];
30
32
  }
31
33
  deleteTopics(options, callback) {
@@ -40,7 +42,7 @@ export class Admin extends Base {
40
42
  callback(validationError, undefined);
41
43
  return callback[kCallbackPromise];
42
44
  }
43
- this.#deleteTopics(options, callback);
45
+ adminTopicsChannel.traceCallback(this.#deleteTopics, 1, createDiagnosticContext({ client: this, operation: 'deleteTopics', options }), this, options, callback);
44
46
  return callback[kCallbackPromise];
45
47
  }
46
48
  listGroups(options, callback) {
@@ -59,7 +61,7 @@ export class Admin extends Base {
59
61
  return callback[kCallbackPromise];
60
62
  }
61
63
  options.types ??= ['classic'];
62
- this.#listGroups(options, callback);
64
+ adminGroupsChannel.traceCallback(this.#listGroups, 1, createDiagnosticContext({ client: this, operation: 'listGroups', options }), this, options, callback);
63
65
  return callback[kCallbackPromise];
64
66
  }
65
67
  describeGroups(options, callback) {
@@ -74,7 +76,7 @@ export class Admin extends Base {
74
76
  callback(validationError, undefined);
75
77
  return callback[kCallbackPromise];
76
78
  }
77
- this.#describeGroups(options, callback);
79
+ adminGroupsChannel.traceCallback(this.#describeGroups, 1, createDiagnosticContext({ client: this, operation: 'describeGroups', options }), this, options, callback);
78
80
  return callback[kCallbackPromise];
79
81
  }
80
82
  deleteGroups(options, callback) {
@@ -89,7 +91,7 @@ export class Admin extends Base {
89
91
  callback(validationError, undefined);
90
92
  return callback[kCallbackPromise];
91
93
  }
92
- this.#deleteGroups(options, callback);
94
+ adminGroupsChannel.traceCallback(this.#deleteGroups, 1, createDiagnosticContext({ client: this, operation: 'deleteGroups', options }), this, options, callback);
93
95
  return callback[kCallbackPromise];
94
96
  }
95
97
  #createTopics(options, callback) {
@@ -150,7 +152,7 @@ export class Admin extends Base {
150
152
  deleteTopicsV6(connection, requests, this[kOptions].timeout, retryCallback);
151
153
  });
152
154
  }, deduplicateCallback, 0);
153
- }, callback);
155
+ }, error => callback(error));
154
156
  }
155
157
  #listGroups(options, callback) {
156
158
  // Find all the brokers in the cluster
@@ -296,9 +298,7 @@ export class Admin extends Base {
296
298
  deleteGroupsV2(connection, groups, retryCallback);
297
299
  }, concurrentCallback, 0);
298
300
  });
299
- }, error => {
300
- callback(error);
301
- });
301
+ }, error => callback(error));
302
302
  });
303
303
  });
304
304
  }
@@ -1,8 +1,10 @@
1
1
  import { type ValidateFunction } from 'ajv';
2
2
  import { EventEmitter } from 'node:events';
3
3
  import { type Callback } from '../../apis/definitions.ts';
4
+ import { type ClientType } from '../../diagnostic.ts';
4
5
  import { ConnectionPool } from '../../network/connection-pool.ts';
5
6
  import { type Broker } from '../../network/connection.ts';
7
+ import { kInstance } from '../../symbols.ts';
6
8
  import { type CallbackWithPromise } from '../callbacks.ts';
7
9
  import { type Metrics } from '../metrics.ts';
8
10
  import { type BaseOptions, type ClusterMetadata, type MetadataOptions } from './types.ts';
@@ -22,20 +24,24 @@ export declare const kPerformDeduplicated: unique symbol;
22
24
  export declare const kValidateOptions: unique symbol;
23
25
  export declare const kInspect: unique symbol;
24
26
  export declare const kFormatValidationErrors: unique symbol;
25
- export declare const kInstance: unique symbol;
26
27
  export declare const kPrometheus: unique symbol;
27
- export declare class Base<OptionsType extends BaseOptions> extends EventEmitter {
28
+ export declare const kClientType: unique symbol;
29
+ export declare const kAfterCreate: unique symbol;
30
+ export declare class Base<OptionsType extends BaseOptions = BaseOptions> extends EventEmitter {
28
31
  #private;
29
32
  [kInstance]: number;
30
33
  [kClientId]: string;
34
+ [kClientType]: ClientType;
31
35
  [kBootstrapBrokers]: Broker[];
32
36
  [kOptions]: OptionsType;
33
37
  [kConnections]: ConnectionPool;
34
38
  [kClosed]: boolean;
35
39
  [kPrometheus]: Metrics | undefined;
36
40
  constructor(options: OptionsType);
41
+ get instanceId(): number;
37
42
  get clientId(): string;
38
43
  get closed(): boolean;
44
+ get type(): ClientType;
39
45
  emitWithDebug(section: string | null, name: string, ...args: any[]): boolean;
40
46
  close(callback: CallbackWithPromise<void>): void;
41
47
  close(): Promise<void>;
@@ -51,4 +57,5 @@ export declare class Base<OptionsType extends BaseOptions> extends EventEmitter
51
57
  [kValidateOptions](target: unknown, validator: ValidateFunction<unknown>, targetName: string, throwOnErrors?: boolean): Error | null;
52
58
  [kInspect](...args: unknown[]): void;
53
59
  [kFormatValidationErrors](validator: ValidateFunction<unknown>, targetName: string): string;
60
+ [kAfterCreate](type: ClientType): void;
54
61
  }
@@ -1,7 +1,9 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import { api as metadataV12 } from "../../apis/metadata/metadata.js";
3
+ import { baseMetadataChannel, createDiagnosticContext, notifyCreation } from "../../diagnostic.js";
3
4
  import { MultipleErrors, NetworkError, UserError } from "../../errors.js";
4
5
  import { ConnectionPool } from "../../network/connection-pool.js";
6
+ import { kInstance } from "../../symbols.js";
5
7
  import { ajv, debugDump, loggers } from "../../utils.js";
6
8
  import { createPromisifiedCallback, kCallbackPromise } from "../callbacks.js";
7
9
  import { baseOptionsValidator, defaultBaseOptions, defaultPort, metadataOptionsValidator } from "./options.js";
@@ -21,14 +23,16 @@ export const kPerformDeduplicated = Symbol('plt.kafka.base.performDeduplicated')
21
23
  export const kValidateOptions = Symbol('plt.kafka.base.validateOptions');
22
24
  export const kInspect = Symbol('plt.kafka.base.inspect');
23
25
  export const kFormatValidationErrors = Symbol('plt.kafka.base.formatValidationErrors');
24
- export const kInstance = Symbol('plt.kafka.base.instance');
25
26
  export const kPrometheus = Symbol('plt.kafka.base.prometheus');
27
+ export const kClientType = Symbol('plt.kafka.base.clientType');
28
+ export const kAfterCreate = Symbol('plt.kafka.base.afterCreate');
26
29
  let currentInstance = 0;
27
30
  export class Base extends EventEmitter {
28
- // This is just used for debugging
31
+ // This is declared using a symbol (a.k.a protected/friend) to make it available in ConnectionPool and MessagesStream
29
32
  [kInstance];
30
33
  // General status - Use symbols rather than JS private property to make them "protected" as in C++
31
34
  [kClientId];
35
+ [kClientType];
32
36
  [kBootstrapBrokers];
33
37
  [kOptions];
34
38
  [kConnections];
@@ -38,6 +42,7 @@ export class Base extends EventEmitter {
38
42
  #inflightDeduplications;
39
43
  constructor(options) {
40
44
  super();
45
+ this[kClientType] = 'base';
41
46
  this[kInstance] = currentInstance++;
42
47
  // Validate options
43
48
  this[kOptions] = Object.assign({}, defaultBaseOptions, options);
@@ -57,19 +62,22 @@ export class Base extends EventEmitter {
57
62
  this[kPrometheus] = options.metrics;
58
63
  }
59
64
  }
60
- /* c8 ignore next 3 */
65
+ get instanceId() {
66
+ return this[kInstance];
67
+ }
61
68
  get clientId() {
62
69
  return this[kClientId];
63
70
  }
64
- /* c8 ignore next 3 */
65
71
  get closed() {
66
72
  return this[kClosed] === true;
67
73
  }
74
+ get type() {
75
+ return this[kClientType];
76
+ }
68
77
  emitWithDebug(section, name, ...args) {
69
78
  if (!section) {
70
79
  return this.emit(name, ...args);
71
80
  }
72
- /* c8 ignore next */
73
81
  loggers[section]?.({ event: name, payload: args });
74
82
  return this.emit(`${section}:${name}`, ...args);
75
83
  }
@@ -90,7 +98,7 @@ export class Base extends EventEmitter {
90
98
  callback(validationError, undefined);
91
99
  return callback[kCallbackPromise];
92
100
  }
93
- this[kMetadata](options, callback);
101
+ baseMetadataChannel.traceCallback(this[kMetadata], 1, createDiagnosticContext({ client: this, operation: 'metadata' }), this, options, callback);
94
102
  return callback[kCallbackPromise];
95
103
  }
96
104
  [kCreateConnectionPool]() {
@@ -135,7 +143,7 @@ export class Base extends EventEmitter {
135
143
  brokers.set(broker.nodeId, { host, port });
136
144
  }
137
145
  for (const { name, topicId: id, partitions: rawPartitions, isInternal } of metadata.topics) {
138
- /* c8 ignore next 3 */
146
+ /* c8 ignore next 3 - Sometimes internal topics might be returned by Kafka */
139
147
  if (isInternal) {
140
148
  continue;
141
149
  }
@@ -242,12 +250,15 @@ export class Base extends EventEmitter {
242
250
  }
243
251
  return null;
244
252
  }
245
- // This is a private API used to debug during development
246
- /* c8 ignore next 3 */
253
+ /* c8 ignore next 3 -- This is a private API used to debug during development */
247
254
  [kInspect](...args) {
248
255
  debugDump(`client:${this[kInstance]}`, ...args);
249
256
  }
250
257
  [kFormatValidationErrors](validator, targetName) {
251
258
  return ajv.errorsText(validator.errors, { dataVar: '$dataVar$' }).replaceAll('$dataVar$', targetName) + '.';
252
259
  }
260
+ [kAfterCreate](type) {
261
+ this[kClientType] = type;
262
+ notifyCreation(type, this);
263
+ }
253
264
  }
@@ -1,5 +1,6 @@
1
1
  import { type Callback } from '../apis/definitions.ts';
2
2
  export declare const kCallbackPromise: unique symbol;
3
+ export declare const kNoopCallbackReturnValue: unique symbol;
3
4
  export declare const noopCallback: CallbackWithPromise<any>;
4
5
  export type CallbackWithPromise<ReturnType> = Callback<ReturnType> & {
5
6
  [kCallbackPromise]?: Promise<ReturnType>;
@@ -1,8 +1,9 @@
1
1
  import { MultipleErrors } from "../errors.js";
2
2
  export const kCallbackPromise = Symbol('plt.kafka.callbackPromise');
3
- /* c8 ignore next 3 */
3
+ // This is only meaningful for testing
4
+ export const kNoopCallbackReturnValue = Symbol('plt.kafka.noopCallbackReturnValue');
4
5
  export const noopCallback = () => {
5
- return Promise.resolve();
6
+ return Promise.resolve(kNoopCallbackReturnValue);
6
7
  };
7
8
  export function createPromisifiedCallback() {
8
9
  const { promise, resolve, reject } = Promise.withResolvers();
@@ -8,10 +8,11 @@ import { api as offsetFetchV9 } from "../../apis/consumer/offset-fetch.js";
8
8
  import { api as syncGroupV5 } from "../../apis/consumer/sync-group.js";
9
9
  import { FetchIsolationLevels, FindCoordinatorKeyTypes } from "../../apis/enumerations.js";
10
10
  import { api as findCoordinatorV6 } from "../../apis/metadata/find-coordinator.js";
11
+ import { consumerCommitsChannel, consumerConsumesChannel, consumerFetchesChannel, consumerGroupChannel, consumerHeartbeatChannel, consumerOffsetsChannel, createDiagnosticContext } from "../../diagnostic.js";
11
12
  import { UserError } from "../../errors.js";
12
13
  import { Reader } from "../../protocol/reader.js";
13
14
  import { Writer } from "../../protocol/writer.js";
14
- import { Base, kBootstrapBrokers, kCheckNotClosed, kClosed, kConnections, kCreateConnectionPool, kFetchConnections, kFormatValidationErrors, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kPrometheus, kValidateOptions } from "../base/base.js";
15
+ import { Base, kAfterCreate, kBootstrapBrokers, kCheckNotClosed, kClosed, kConnections, kCreateConnectionPool, kFetchConnections, kFormatValidationErrors, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kPrometheus, kValidateOptions } from "../base/base.js";
15
16
  import { defaultBaseOptions } from "../base/options.js";
16
17
  import { createPromisifiedCallback, kCallbackPromise, runConcurrentCallbacks } from "../callbacks.js";
17
18
  import { ensureMetric } from "../metrics.js";
@@ -72,6 +73,7 @@ export class Consumer extends Base {
72
73
  this.#metricActiveStreams = ensureMetric(this[kPrometheus], 'Gauge', 'kafka_consumers_streams', 'Number of active Kafka consumers streams');
73
74
  this.topics.setMetric(ensureMetric(this[kPrometheus], 'Gauge', 'kafka_consumers_topics', 'Number of topics being consumed'));
74
75
  }
76
+ this[kAfterCreate]('consumer');
75
77
  }
76
78
  get streamsCount() {
77
79
  return this.#streams.size;
@@ -153,7 +155,7 @@ export class Consumer extends Base {
153
155
  callback(validationError, undefined);
154
156
  return callback[kCallbackPromise];
155
157
  }
156
- this.#fetch(options, callback);
158
+ consumerFetchesChannel.traceCallback(this.#fetch, 1, createDiagnosticContext({ client: this, operation: 'fetch', options }), this, options, callback);
157
159
  return callback[kCallbackPromise];
158
160
  }
159
161
  commit(options, callback) {
@@ -168,7 +170,7 @@ export class Consumer extends Base {
168
170
  callback(validationError);
169
171
  return callback[kCallbackPromise];
170
172
  }
171
- this.#commit(options, callback);
173
+ consumerCommitsChannel.traceCallback(this.#commit, 1, createDiagnosticContext({ client: this, operation: 'commit', options }), this, options, callback);
172
174
  return callback[kCallbackPromise];
173
175
  }
174
176
  listOffsets(options, callback) {
@@ -183,7 +185,7 @@ export class Consumer extends Base {
183
185
  callback(validationError, undefined);
184
186
  return callback[kCallbackPromise];
185
187
  }
186
- this.#listOffsets(options, callback);
188
+ consumerOffsetsChannel.traceCallback(this.#listOffsets, 1, createDiagnosticContext({ client: this, operation: 'listOffsets', options }), this, options, callback);
187
189
  return callback[kCallbackPromise];
188
190
  }
189
191
  listCommittedOffsets(options, callback) {
@@ -198,7 +200,7 @@ export class Consumer extends Base {
198
200
  callback(validationError, undefined);
199
201
  return callback[kCallbackPromise];
200
202
  }
201
- this.#listCommittedOffsets(options, callback);
203
+ consumerOffsetsChannel.traceCallback(this.#listCommittedOffsets, 1, createDiagnosticContext({ client: this, operation: 'listCommittedOffsets', options }), this, options, callback);
202
204
  return callback[kCallbackPromise];
203
205
  }
204
206
  findGroupCoordinator(callback) {
@@ -258,37 +260,8 @@ export class Consumer extends Base {
258
260
  });
259
261
  return callback[kCallbackPromise];
260
262
  }
261
- #consume(options, callback, trackTopics = true) {
262
- // Subscribe all topics
263
- let joinNeeded = this.memberId === null;
264
- if (trackTopics) {
265
- for (const topic of options.topics) {
266
- if (this.topics.track(topic)) {
267
- joinNeeded = true;
268
- }
269
- }
270
- }
271
- // If we need to (re)join the group, do that first and then try again
272
- if (joinNeeded) {
273
- this.joinGroup(options, error => {
274
- if (error) {
275
- callback(error, undefined);
276
- return;
277
- }
278
- this.#consume(options, callback, false);
279
- });
280
- return callback[kCallbackPromise];
281
- }
282
- // Create the stream and start consuming
283
- const stream = new MessagesStream(this, options);
284
- this.#streams.add(stream);
285
- this.#metricActiveStreams?.inc();
286
- stream.once('close', () => {
287
- this.#metricActiveStreams?.dec();
288
- this.#streams.delete(stream);
289
- });
290
- callback(null, stream);
291
- return callback[kCallbackPromise];
263
+ #consume(options, callback) {
264
+ consumerConsumesChannel.traceCallback(this.#performConsume, 2, createDiagnosticContext({ client: this, operation: 'consume', options }), this, options, true, callback);
292
265
  }
293
266
  #fetch(options, callback) {
294
267
  this[kPerformWithRetry]('fetch', retryCallback => {
@@ -427,6 +400,91 @@ export class Consumer extends Base {
427
400
  callback(null, this.#coordinatorId);
428
401
  return;
429
402
  }
403
+ consumerGroupChannel.traceCallback(this.#performFindGroupCoordinator, 0, createDiagnosticContext({ client: this, operation: 'findGroupCoordinator' }), this, callback);
404
+ }
405
+ #joinGroup(options, callback) {
406
+ consumerGroupChannel.traceCallback(this.#performJoinGroup, 1, createDiagnosticContext({ client: this, operation: 'joinGroup', options }), this, options, callback);
407
+ }
408
+ #leaveGroup(force, callback) {
409
+ consumerGroupChannel.traceCallback(this.#performLeaveGroup, 1, createDiagnosticContext({ client: this, operation: 'leaveGroup', force }), this, force, callback);
410
+ }
411
+ #syncGroup(callback) {
412
+ consumerGroupChannel.traceCallback(this.#performSyncGroup, 1, createDiagnosticContext({ client: this, operation: 'syncGroup' }), this, null, callback);
413
+ }
414
+ #heartbeat(options) {
415
+ const eventPayload = { groupId: this.groupId, memberId: this.memberId, generationId: this.generationId };
416
+ consumerHeartbeatChannel.traceCallback((this.#performDeduplicateGroupOperaton), 2, createDiagnosticContext({ client: this, operation: 'heartbeat' }), this, 'heartbeat', (connection, groupCallback) => {
417
+ // We have left the group in the meanwhile, abort
418
+ if (!this.#membershipActive) {
419
+ this.emitWithDebug('consumer:heartbeat', 'cancel', eventPayload);
420
+ return;
421
+ }
422
+ this.emitWithDebug('consumer:heartbeat', 'start', eventPayload);
423
+ heartbeatV4(connection, this.groupId, this.generationId, this.memberId, null, groupCallback);
424
+ }, error => {
425
+ // The heartbeat has been aborted elsewhere, ignore the response
426
+ if (this.#heartbeatInterval === null || !this.#membershipActive) {
427
+ this.emitWithDebug('consumer:heartbeat', 'cancel', eventPayload);
428
+ return;
429
+ }
430
+ if (error) {
431
+ this.#cancelHeartbeat();
432
+ if (this.#getRejoinError(error)) {
433
+ this[kPerformWithRetry]('rejoinGroup', retryCallback => {
434
+ this.#joinGroup(options, retryCallback);
435
+ }, error => {
436
+ if (error) {
437
+ this.emitWithDebug(null, 'error', error);
438
+ }
439
+ this.emitWithDebug('consumer', 'rejoin');
440
+ }, 0);
441
+ return;
442
+ }
443
+ this.emitWithDebug('consumer:heartbeat', 'error', { ...eventPayload, error });
444
+ // Note that here we purposely do not return, since it was not a group related problem we schedule another heartbeat
445
+ }
446
+ else {
447
+ this.emitWithDebug('consumer:heartbeat', 'end', eventPayload);
448
+ }
449
+ this.#heartbeatInterval?.refresh();
450
+ });
451
+ }
452
+ #cancelHeartbeat() {
453
+ clearTimeout(this.#heartbeatInterval);
454
+ this.#heartbeatInterval = null;
455
+ }
456
+ #performConsume(options, trackTopics, callback) {
457
+ // Subscribe all topics
458
+ let joinNeeded = this.memberId === null;
459
+ if (trackTopics) {
460
+ for (const topic of options.topics) {
461
+ if (this.topics.track(topic)) {
462
+ joinNeeded = true;
463
+ }
464
+ }
465
+ }
466
+ // If we need to (re)join the group, do that first and then try again
467
+ if (joinNeeded) {
468
+ this.joinGroup(options, error => {
469
+ if (error) {
470
+ callback(error, undefined);
471
+ return;
472
+ }
473
+ this.#performConsume(options, false, callback);
474
+ });
475
+ return;
476
+ }
477
+ // Create the stream and start consuming
478
+ const stream = new MessagesStream(this, options);
479
+ this.#streams.add(stream);
480
+ this.#metricActiveStreams?.inc();
481
+ stream.once('close', () => {
482
+ this.#metricActiveStreams?.dec();
483
+ this.#streams.delete(stream);
484
+ });
485
+ callback(null, stream);
486
+ }
487
+ #performFindGroupCoordinator(callback) {
430
488
  this[kPerformDeduplicated]('findGroupCoordinator', deduplicateCallback => {
431
489
  this[kPerformWithRetry]('findGroupCoordinator', retryCallback => {
432
490
  this[kConnections].getFirstAvailable(this[kBootstrapBrokers], (error, connection) => {
@@ -447,7 +505,7 @@ export class Consumer extends Base {
447
505
  }, 0);
448
506
  }, callback);
449
507
  }
450
- #joinGroup(options, callback) {
508
+ #performJoinGroup(options, callback) {
451
509
  if (!this.#membershipActive) {
452
510
  callback(null, undefined);
453
511
  return;
@@ -469,7 +527,7 @@ export class Consumer extends Base {
469
527
  }
470
528
  if (error) {
471
529
  if (this.#getRejoinError(error)) {
472
- this.#joinGroup(options, callback);
530
+ this.#performJoinGroup(options, callback);
473
531
  return;
474
532
  }
475
533
  callback(error, undefined);
@@ -483,14 +541,14 @@ export class Consumer extends Base {
483
541
  this.#members.set(member.memberId, this.#decodeProtocolSubscriptionMetadata(member.memberId, member.metadata));
484
542
  }
485
543
  // Send a syncGroup request
486
- this.#syncGroup(null, (error, response) => {
544
+ this.#syncGroup((error, response) => {
487
545
  if (!this.#membershipActive) {
488
546
  callback(null, undefined);
489
547
  return;
490
548
  }
491
549
  if (error) {
492
550
  if (this.#getRejoinError(error)) {
493
- this.#joinGroup(options, callback);
551
+ this.#performJoinGroup(options, callback);
494
552
  return;
495
553
  }
496
554
  callback(error, undefined);
@@ -512,7 +570,7 @@ export class Consumer extends Base {
512
570
  });
513
571
  });
514
572
  }
515
- #leaveGroup(force, callback) {
573
+ #performLeaveGroup(force, callback) {
516
574
  if (!this.memberId) {
517
575
  callback(null);
518
576
  return;
@@ -536,7 +594,7 @@ export class Consumer extends Base {
536
594
  return;
537
595
  }
538
596
  // All streams are closed, try the operation again without force
539
- this.#leaveGroup(false, callback);
597
+ this.#performLeaveGroup(false, callback);
540
598
  });
541
599
  return;
542
600
  }
@@ -563,7 +621,7 @@ export class Consumer extends Base {
563
621
  callback(null);
564
622
  });
565
623
  }
566
- #syncGroup(assignments, callback) {
624
+ #performSyncGroup(assignments, callback) {
567
625
  if (!this.#membershipActive) {
568
626
  callback(null, []);
569
627
  return;
@@ -587,7 +645,7 @@ export class Consumer extends Base {
587
645
  callback(error, undefined);
588
646
  return;
589
647
  }
590
- this.#syncGroup(this.#roundRobinAssignments(metadata), callback);
648
+ this.#performSyncGroup(this.#roundRobinAssignments(metadata), callback);
591
649
  });
592
650
  return;
593
651
  }
@@ -618,48 +676,6 @@ export class Consumer extends Base {
618
676
  callback(error, assignments);
619
677
  });
620
678
  }
621
- #heartbeat(options) {
622
- const eventPayload = { groupId: this.groupId, memberId: this.memberId, generationId: this.generationId };
623
- this.#performDeduplicateGroupOperaton('heartbeat', (connection, groupCallback) => {
624
- // We have left the group in the meanwhile, abort
625
- if (!this.#membershipActive) {
626
- this.emitWithDebug('consumer:heartbeat', 'cancel', eventPayload);
627
- return;
628
- }
629
- this.emitWithDebug('consumer:heartbeat', 'start', eventPayload);
630
- heartbeatV4(connection, this.groupId, this.generationId, this.memberId, null, groupCallback);
631
- }, error => {
632
- // The heartbeat has been aborted elsewhere, ignore the response
633
- if (this.#heartbeatInterval === null || !this.#membershipActive) {
634
- this.emitWithDebug('consumer:heartbeat', 'cancel', eventPayload);
635
- return;
636
- }
637
- if (error) {
638
- this.#cancelHeartbeat();
639
- if (this.#getRejoinError(error)) {
640
- this[kPerformWithRetry]('rejoinGroup', retryCallback => {
641
- this.#joinGroup(options, retryCallback);
642
- }, error => {
643
- if (error) {
644
- this.emitWithDebug(null, 'error', error);
645
- }
646
- this.emitWithDebug('consumer', 'rejoin');
647
- }, 0);
648
- return;
649
- }
650
- this.emitWithDebug('consumer:heartbeat', 'error', { ...eventPayload, error });
651
- // Note that here we purposely do not return, since it was not a group related problem we schedule another heartbeat
652
- }
653
- else {
654
- this.emitWithDebug('consumer:heartbeat', 'end', eventPayload);
655
- }
656
- this.#heartbeatInterval?.refresh();
657
- });
658
- }
659
- #cancelHeartbeat() {
660
- clearTimeout(this.#heartbeatInterval);
661
- this.#heartbeatInterval = null;
662
- }
663
679
  #performDeduplicateGroupOperaton(operationId, operation, callback) {
664
680
  return this[kPerformDeduplicated](operationId, deduplicateCallback => {
665
681
  this.#performGroupOperation(operationId, operation, deduplicateCallback);
@@ -5,6 +5,7 @@ import { type CallbackWithPromise } from '../callbacks.ts';
5
5
  import { type Consumer } from './consumer.ts';
6
6
  import { type CommitOptionsPartition, type ConsumeOptions } from './types.ts';
7
7
  export declare function noopDeserializer(data?: Buffer): Buffer | undefined;
8
+ export declare function defaultCorruptedMessageHandler(): boolean;
8
9
  export declare class MessagesStream<Key, Value, HeaderKey, HeaderValue> extends Readable {
9
10
  #private;
10
11
  constructor(consumer: Consumer<Key, Value, HeaderKey, HeaderValue>, options: ConsumeOptions<Key, Value, HeaderKey, HeaderValue>);