@escueladigital/micro
Version:
Microservice manager for nodejs with kafka
155 lines (139 loc) • 4.4 kB
JavaScript
/* eslint-disable no-console */
/* eslint-disable class-methods-use-this */
/**
* Validaciones :
* 1.- Falta validar que cuando este en local
o produccion no se solicite el sasl
* 2.- Se tiene que eliminar el archivo pubsub.js ya no es necesario
* 3.- Falta implementar error reporter
* 4.- Falta implementar trace
* 5.- Implementar Circuit Breaker
* 6.- Control de fallos.
*/
const { Kafka } = require('kafkajs')
const { name } = require(`${process.cwd()}/package.json`)
const uuidPackage = require('uuid')
const chalk = require('chalk')
const environment = process.env.NODE_ENV
class Pubsub {
constructor(logger) {
this.logger = logger
const host = process.env.KAFKA_ADDRESS || '192.168.8.14'
const sasl =
environment === 'local'
? null
: {
mechanism: 'plain', // scram-sha-256 or scram-sha-512
username: process.env.KAFKA_USER,
password: process.env.KAFKA_PASSWORD,
}
this.kafka = new Kafka({
brokers: [`${host}:9092`],
clientId: `${name}_client${environment}3`,
sasl,
})
this.consumer = this.kafka.consumer({
groupId: `${name}-consumer-${environment}2`,
})
this.parasite = this.kafka.consumer({
groupId: `${name}-consumer-${environment}-parasite3`,
})
this.producer = this.kafka.producer()
this.admin = this.kafka.admin()
this.reqResources = {}
}
nameTopic(topic) {
return `${process.env.NODE_ENV}.${topic}`
}
async getMicroTopics(deleteTopics = []) {
const { topics } = await this.admin.fetchTopicMetadata()
let allTopics = []
for (let i = 0; i < deleteTopics.length; i += 1) {
const microtopic = topics.filter(topic => topic.name.includes(`micro.${deleteTopics[i]}.`))
allTopics = allTopics.concat(microtopic)
}
return allTopics
}
timeOut(promise, TIME) {
setTimeout(() => promise.reject(new Error('Micro no contesto')), TIME)
}
async openConnection() {
await this.consumer.connect()
await this.admin.connect()
await this.producer.connect()
}
async rpc(topic, args) {
const envTopic = this.nameTopic(topic)
return new Promise(async (resolve, reject) => {
const id = uuidPackage()
try {
const data = { uuid: id, arg: args || {} }
this.reqResources[id] = { resolve, reject }
await this.writeMessageToMicro(JSON.stringify(data), envTopic)
setTimeout(
() => reject(new Error('RPC no contesto, revisar topic name')),
process.env.MICRO_TIME_OUT || 3000
)
} catch (e) {
delete this.reqResources[id]
reject(e.toString())
}
})
}
async closeConnection() {
await this.producer.disconnect()
await this.admin.disconnect()
await this.consumer.disconnect()
}
// Carga las subscripciones de todos los topicos asociados.
async loadSubscription(topic) {
await this.consumer.subscribe({ topic: topic.req })
}
async setUpProject(topics) {
const proccesedTopics = topics.map(topic => ({ topic: topic.req }))
const proccesedTopicsRes = topics.map(topic => ({ topic: topic.res }))
const proccesedTopicsMicro = topics.map(topic => ({ topic: topic.micro }))
const resulted = proccesedTopics.concat(proccesedTopicsRes)
const withMicro = resulted.concat(proccesedTopicsMicro)
this.logger.info(chalk.bgGreen(chalk.black('*** CREATING TOPICS ***')))
for (let i = 0; i < withMicro.length; i += 1) {
const topic = withMicro[i]
try {
await this.admin.createTopics({ topics: [topic] })
} catch (e) {
console.log('e')
}
}
this.logger.info(chalk.bgGreen(chalk.black('*** CREATING TOPICS - END ***')))
}
async writeMessageToMicro(value, topic) {
this.logger.info(topic)
this.logger.info(value)
try {
await this.producer.send({
topic,
messages: [{ value, headers: { responseKind: 'micro' } }],
})
} catch (e) {
console.log(e)
}
}
async writeMessageToTopic(value, topic, responseKind = 'none') {
try {
await this.producer.send({
topic: this.nameTopic(topic),
messages: [
{
value,
headers: {
responseKind,
},
},
],
})
} catch (e) {
console.log(e)
}
}
}
module.exports = Pubsub