From 392cf4568b7cd752e5c0abf804ddcf9094ecc537 Mon Sep 17 00:00:00 2001 From: Milind L Date: Fri, 13 Dec 2024 16:39:06 +0530 Subject: [PATCH 1/3] Add error types to declaration file --- lib/kafkajs/_error.js | 36 +++++++++++++-- types/kafkajs.d.ts | 104 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/lib/kafkajs/_error.js b/lib/kafkajs/_error.js index 27584cbf..f00973f7 100644 --- a/lib/kafkajs/_error.js +++ b/lib/kafkajs/_error.js @@ -130,10 +130,34 @@ class KafkaJSTimeout extends KafkaJSError { } } -class KafkaJSLockTimeout extends KafkaJSTimeout { - constructor() { - super(...arguments); - this.name = 'KafkaJSLockTimeout'; +class KafkaJSCreateTopicError extends KafkaJSProtocolError { + constructor(e, topicName, properties) { + super(e, properties); + this.topic = topicName; + this.name = 'KafkaJSCreateTopicError'; + } +} + +class KafkaJSDeleteGroupsError extends KafkaJSError { + constructor(e, groups) { + super(e); + this.groups = groups || []; + this.name = 'KafkaJSDeleteGroupsError'; + } +} + +class KafkaJSDeleteTopicRecordsError extends KafkaJSError { + constructor({ partitions }) { + /* + * This error is retriable if all the errors were retriable + */ + const retriable = partitions + .filter(({ error }) => error !== null) + .every(({ error }) => error.retriable === true); + + super('Error while deleting records', { retriable }); + this.name = 'KafkaJSDeleteTopicRecordsError'; + this.partitions = partitions; } } @@ -186,7 +210,9 @@ module.exports = { KafkaJSGroupCoordinatorNotFound, KafkaJSNotImplemented, KafkaJSTimeout, - KafkaJSLockTimeout, + KafkaJSCreateTopicError, + KafkaJSDeleteGroupsError, + KafkaJSDeleteTopicRecordsError, KafkaJSAggregateError, KafkaJSNoBrokerAvailableError, isRebalancing, diff --git a/types/kafkajs.d.ts b/types/kafkajs.d.ts index 05ba626e..1aaf2817 100644 --- a/types/kafkajs.d.ts +++ b/types/kafkajs.d.ts @@ -12,6 +12,10 @@ import { IsolationLevel } from './rdkafka' +import { + CODES +} from './errors'; + // Admin API related interfaces, types etc; and Error types are common, so // just re-export them from here too. export { @@ -24,7 +28,7 @@ export { Node, AclOperationTypes, Uuid, - IsolationLevel + IsolationLevel, } from './rdkafka' export interface OauthbearerProviderResponse { @@ -427,3 +431,101 @@ export type Admin = { isolationLevel: IsolationLevel }): Promise> } + + +export function isKafkaJSError(error: Error): boolean; + +export const ErrorCodes: typeof CODES.ERRORS; + +export class KafkaJSError extends Error { + readonly message: Error['message'] + readonly name: string + readonly retriable: boolean + readonly fatal: boolean + readonly abortable: boolean + readonly code: number + constructor(e: Error | string, metadata?: KafkaJSErrorMetadata) +} + +export class KafkaJSProtocolError extends KafkaJSError { + constructor(e: Error | string) +} + +export class KafkaJSCreateTopicError extends KafkaJSError { + readonly topic: string + constructor(e: Error | string, topicName: string, metadata?: KafkaJSErrorMetadata) +} + +export class KafkaJSDeleteGroupsError extends KafkaJSError { + readonly groups: DeleteGroupsResult[] + constructor(e: Error | string, groups?: KafkaJSDeleteGroupsErrorGroups[]) +} + +export class KafkaJSDeleteTopicRecordsError extends KafkaJSError { + readonly partitions: KafkaJSDeleteTopicRecordsErrorPartition[] + constructor(metadata: KafkaJSDeleteTopicRecordsErrorTopic) +} + +export interface KafkaJSDeleteGroupsErrorGroups { + groupId: string + errorCode: number + error: KafkaJSError +} + +export interface KafkaJSDeleteTopicRecordsErrorTopic { + topic: string + partitions: KafkaJSDeleteTopicRecordsErrorPartition[] +} + +export interface KafkaJSDeleteTopicRecordsErrorPartition { + partition: number + offset: string + error: KafkaJSError +} + +export class KafkaJSAggregateError extends Error { + readonly errors: (Error | string)[] + constructor(message: Error | string, errors: (Error | string)[]) +} + +export class KafkaJSOffsetOutOfRange extends KafkaJSProtocolError { + readonly topic: string + readonly partition: number + constructor(e: Error | string, metadata?: KafkaJSErrorMetadata) +} + +export class KafkaJSConnectionError extends KafkaJSError { + constructor(e: Error | string, metadata?: KafkaJSErrorMetadata) +} + +export class KafkaJSRequestTimeoutError extends KafkaJSError { + constructor(e: Error | string, metadata?: KafkaJSErrorMetadata) +} + +export class KafkaJSPartialMessageError extends KafkaJSError { + constructor() +} + +export class KafkaJSSASLAuthenticationError extends KafkaJSError { + constructor() +} + +export class KafkaJSGroupCoordinatorNotFound extends KafkaJSError { + constructor() +} + +export class KafkaJSNotImplemented extends KafkaJSError { + constructor() +} + +export class KafkaJSTimeout extends KafkaJSError { + constructor() +} + +export interface KafkaJSErrorMetadata { + retriable?: boolean + fatal?: boolean + abortable?: boolean + stack?: string + code?: number +} From cb5dd3d539e5f7e041c2c9a4c05861aed7c73a23 Mon Sep 17 00:00:00 2001 From: Milind L Date: Fri, 13 Dec 2024 16:44:12 +0530 Subject: [PATCH 2/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1128cc7e..4f525c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ v1.0.0 is a feature release. It is supported for all usage. 1. Add support for an Admin API to fetch topic offsets (#156). 2. Add support for Node v23 pre-built binaries (#158). +3. Include error types within Type definitions for promisified API (#210). ## Fixes From e607630eb41648e393e3950793734f22c2cdeb1d Mon Sep 17 00:00:00 2001 From: Milind L Date: Sun, 15 Dec 2024 10:34:32 +0530 Subject: [PATCH 3/3] Change linting as per review comments --- .semaphore/semaphore.yml | 4 ++-- Makefile | 2 +- src/admin.cc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index ed71e4aa..2bad9391 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -107,9 +107,9 @@ blocks: - docker compose up -d && sleep 30 - export NODE_OPTIONS='--max-old-space-size=1536' - npx jest --no-colors --ci test/promisified/ - - name: "ESLint" + - name: "Lint" commands: - - npx eslint lib/kafkajs + - make lint - name: "Docs" commands: - make docs diff --git a/Makefile b/Makefile index 82b9571a..b231dc21 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ cpplint: @$(PYTHON) $(CPPLINT) --filter=$(CPPLINT_FILTER) $(CPPLINT_FILES) eslint: node_modules/.dirstamp - @./node_modules/.bin/eslint . + @./node_modules/.bin/eslint lib lib: node_modules/.dirstamp $(CONFIG_OUTPUTS) @PYTHONHTTPSVERIFY=0 $(NODE-GYP) build $(GYPBUILDARGS) diff --git a/src/admin.cc b/src/admin.cc index 5cef8047..568cf710 100644 --- a/src/admin.cc +++ b/src/admin.cc @@ -998,8 +998,8 @@ NAN_METHOD(AdminClient::NodeConnect) { // on the background thread. // We will deactivate them if the connection fails. // Because the Admin Client connect is synchronous, we can do this within - // AdminClient::Connect as well, but we do it here to keep the code similiar to - // the Producer and Consumer. + // AdminClient::Connect as well, but we do it here to keep the code similiar + // to the Producer and Consumer. client->ActivateDispatchers(); Baton b = client->Connect();