fix(Kafka Node): Upgrade kafkajs and add tests (#14326)

Co-authored-by: Dana Lee <dana@n8n.io>
This commit is contained in:
Elias Meire
2025-04-02 17:12:42 +02:00
committed by GitHub
parent db381492a9
commit 5c58e8e8cf
7 changed files with 723 additions and 72 deletions

View File

@@ -183,7 +183,7 @@ export class KafkaTrigger implements INodeType {
const credentials = await this.getCredentials('kafka');
const brokers = ((credentials.brokers as string) || '').split(',').map((item) => item.trim());
const brokers = ((credentials.brokers as string) ?? '').split(',').map((item) => item.trim());
const clientId = credentials.clientId as string;
@@ -214,14 +214,19 @@ export class KafkaTrigger implements INodeType {
} as SASLOptions;
}
const kafka = new apacheKafka(config);
const maxInFlightRequests = (
this.getNodeParameter('options.maxInFlightRequests', null) === 0
? null
: this.getNodeParameter('options.maxInFlightRequests', null)
) as number;
const parallelProcessing = options.parallelProcessing as boolean;
const useSchemaRegistry = this.getNodeParameter('useSchemaRegistry', 0) as boolean;
const schemaRegistryUrl = this.getNodeParameter('schemaRegistryUrl', 0) as string;
const kafka = new apacheKafka(config);
const consumer = kafka.consumer({
groupId,
maxInFlightRequests,
@@ -229,17 +234,16 @@ export class KafkaTrigger implements INodeType {
heartbeatInterval: this.getNodeParameter('options.heartbeatInterval', 3000) as number,
});
const parallelProcessing = options.parallelProcessing as boolean;
await consumer.connect();
await consumer.subscribe({ topic, fromBeginning: options.fromBeginning ? true : false });
const useSchemaRegistry = this.getNodeParameter('useSchemaRegistry', 0) as boolean;
const schemaRegistryUrl = this.getNodeParameter('schemaRegistryUrl', 0) as string;
// The "closeFunction" function gets called by n8n whenever
// the workflow gets deactivated and can so clean up.
async function closeFunction() {
await consumer.disconnect();
}
const startConsumer = async () => {
await consumer.connect();
await consumer.subscribe({ topic, fromBeginning: options.fromBeginning ? true : false });
await consumer.run({
autoCommitInterval: (options.autoCommitInterval as number) || null,
autoCommitThreshold: (options.autoCommitThreshold as number) || null,
@@ -261,13 +265,12 @@ export class KafkaTrigger implements INodeType {
}
if (options.returnHeaders && message.headers) {
const headers: { [key: string]: string } = {};
for (const key of Object.keys(message.headers)) {
const header = message.headers[key];
headers[key] = header?.toString('utf8') || '';
}
data.headers = headers;
data.headers = Object.fromEntries(
Object.entries(message.headers).map(([headerKey, headerValue]) => [
headerKey,
headerValue?.toString('utf8') ?? '',
]),
);
}
data.message = value;
@@ -291,27 +294,24 @@ export class KafkaTrigger implements INodeType {
});
};
await startConsumer();
// The "closeFunction" function gets called by n8n whenever
// the workflow gets deactivated and can so clean up.
async function closeFunction() {
await consumer.disconnect();
}
// The "manualTriggerFunction" function gets called by n8n
// when a user is in the workflow editor and starts the
// workflow manually. So the function has to make sure that
// the emit() gets called with similar data like when it
// would trigger by itself so that the user knows what data
// to expect.
async function manualTriggerFunction() {
if (this.getMode() !== 'manual') {
await startConsumer();
}
return { closeFunction };
} else {
// The "manualTriggerFunction" function gets called by n8n
// when a user is in the workflow editor and starts the
// workflow manually. So the function has to make sure that
// the emit() gets called with similar data like when it
// would trigger by itself so that the user knows what data
// to expect.
async function manualTriggerFunction() {
await startConsumer();
}
return {
closeFunction,
manualTriggerFunction,
};
return {
closeFunction,
manualTriggerFunction,
};
}
}
}