@awesomeniko/kafka-trail
Version:
A Node.js library for managing message queue with Kafka
101 lines • 3.62 kB
JavaScript
import Kafka, { CompressionTypes } from "kafkajs";
import { UnableDecreasePartitionsError } from "../custom-errors/kafka-errors.js";
import { CustomPartitioner } from "./custom-partitioner.js";
import { KTKafkaBroker } from "./kafka-broker.js";
class KTKafkaProducer extends KTKafkaBroker {
#producer;
#admin;
#logger;
#compressionType;
constructor(params) {
super(params);
const { createPartitioner, logger } = params;
let customPartitioner = createPartitioner;
if (!customPartitioner) {
customPartitioner = CustomPartitioner.roundRobin;
}
this.#producer = this._kafka.producer({
createPartitioner: customPartitioner,
allowAutoTopicCreation: false,
});
this.#admin = this._kafka.admin();
this.#logger = logger;
this.#compressionType = params.kafkaSettings.compressionCodec?.codecType ?? CompressionTypes.LZ4;
}
getAdmin() {
return this.#admin;
}
init() {
return Promise.all([this.#admin.connect(), this.#producer.connect()]);
}
destroy() {
return Promise.all([this.#admin.disconnect(), this.#producer.disconnect()]);
}
async createTopic(topicConfig) {
this.#logger.info({
topicName: topicConfig.topic,
topicConfig,
}, "Resolving topics...");
try {
const topicMetadata = await this.#admin.fetchTopicMetadata({ topics: [topicConfig.topic] });
const currentTopic = topicMetadata.topics.find((topicMetadata) => topicMetadata.name === topicConfig.topic);
if (!currentTopic) {
throw new Kafka.KafkaJSProtocolError('Topic not found');
}
if (topicConfig.numPartitions === currentTopic.partitions.length) {
return;
}
if ((topicConfig.numPartitions || 0) > currentTopic.partitions.length) {
await this.#admin.createPartitions({
topicPartitions: [
{
topic: topicConfig.topic,
count: topicConfig.numPartitions || 0,
},
],
});
this.#logger.info(`Expanded partitions for ${topicConfig.topic} topic`);
}
else {
throw new UnableDecreasePartitionsError();
}
this.#logger.info("Topics resolved successful");
}
catch (e) {
if (e instanceof Kafka.KafkaJSProtocolError) {
await this.#admin.createTopics({
topics: [topicConfig],
waitForLeaders: true,
});
}
else {
this.#logger.error(e, "Error from createTopic");
throw e;
}
}
}
async sendSingleMessage(params) {
const { topicName, messageKey, value, headers } = params;
await this.#producer.send({
topic: topicName,
compression: this.#compressionType,
messages: [
{
key: messageKey ?? null,
value,
headers,
},
],
});
}
async sendBatchMessages(params) {
const { topicName, messages } = params;
await this.#producer.send({
topic: topicName,
compression: this.#compressionType,
messages,
});
}
}
export { KTKafkaProducer };
//# sourceMappingURL=kafka-producer.js.map