UNPKG

@awesomeniko/kafka-trail

Version:

A Node.js library for managing message queue with Kafka

101 lines 3.62 kB
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