I'm looking for a good pattern to follow that combines Javascript classes, event listeners, and async programming.
I'm trying to write a shared library for my project that handles connections to a Kafka server. The kafka-node library requires that you connect and then set a listener for a 'connected' event. I would like to mask that complexity for other libraries that need to produce messages to kafka.
The following code essentially works, but I feel that it's complex (resolving the Promise within an event listener) and there must be a better way
class KafkaProducer {
constructor(id) {
this.connected_mode = process.env.KAFKA_CONNECT !== 'false';
this.hostname = process.env.NODE_ENV === 'development' ? '192.168.99.100:2181' : 'service-kafka:2181';
this.id = id ? id : 'no_name_specified';
log.info(`KafkaProducer: hostname: ${this.hostname} id: ${this.id}`);
if (this.connected_mode === false) {
log.info('KafkaProducer: Running in disconnected mode');
this.ready = true;
return;
}
this.client = new Client(this.hostname, this.id, {
sessionTimeout: 300,
spinDelay: 100,
retries: 2
});
this.ready = false;
this.connected = false;
this.producer = false;
this.metrics = {};
}
initialize() {
let that = this;
log.silly(`KafkaProducer.initialize: Initializing with connected_mode=${this.connected_mode}`);
return new Promise((resolve, reject) => {
if (that.connected_mode === false) {
log.silly('KafkaProducer.initialize: Returning early in disconnected mode');
return resolve();
}
if (that.ready && that.producer) {
log.silly('KafkaProducer.initialize: Returning early as both ready and producer are set');
return resolve();
}
log.silly(`KafkaProducer.initialize: Creating Producer with client details connectionString=${that.client.connectionString}`)
that.producer = new Producer(that.client, {requireAcks: 1});
that.producer.on('ready', () => {
log.info('KafkaProducer: Producer is ready');
that.ready = true;
that.connected = true;
return resolve();
});
that.producer.on('error', (err) => {
log.error(`KafkaProducer: ${err}`);
});
});
}
Other code that needs to send a Kafka message can import this class, check the ready attribute and initialize if necessary
KafkaProducer.initialize().then(() => {
KafkaProducer.sendMessage('foo');
});
But resolving the Promise from within an event listener smells like bad code. Is there a better way?
Edit: I mistakenly wrote "return" the promise rather than "resolve"... Have corrected the question