UNPKG

ihub-framework-js

Version:

Legacy version of iHub Framework written in Javascript

144 lines (121 loc) 4.36 kB
const amqp = require('amqplib/callback_api'); const log = require('winston'); const { RABBIT_USER = '', RABBIT_PASS = '', RABBIT_HOST = 'rabbit', RABBIT_PORT = '', RABBIT_VHOST_NAME = '', RABBIT_HEARTBEAT = '', } = process.env; if (!RABBIT_HOST) { throw new Error('RABBIT_HOST variable cannot be empty'); } // https://www.rabbitmq.com/uri-spec.html let connectionUri = 'amqp://'; if (RABBIT_USER) { connectionUri += RABBIT_USER; if (RABBIT_PASS) { connectionUri += `:${RABBIT_PASS}`; } connectionUri += '@'; } connectionUri += RABBIT_HOST; if (RABBIT_PORT) { connectionUri += `:${RABBIT_PORT}`; } if (RABBIT_VHOST_NAME) { connectionUri += `/${RABBIT_VHOST_NAME}`; } if (RABBIT_HEARTBEAT) { connectionUri += `?heartbeat=${RABBIT_HEARTBEAT}`; } module.exports = apm => ( new Promise((resolve, reject) => { amqp.connect(connectionUri, (connectError, conn) => { if (connectError) { reject(connectError); return; } let cleanUri = connectionUri; if (RABBIT_PASS) { cleanUri = cleanUri.replace(`:${RABBIT_PASS}`, ''); } if (RABBIT_USER) { cleanUri = cleanUri.replace(`${RABBIT_USER}@`, ''); } /* Debug */ log.debug(`Rabbit connected at ${cleanUri} with user '${RABBIT_USER}'`); conn.createChannel((channelError, ch) => { if (channelError) { reject(channelError); return; } /* Debug */ log.debug('Rabbit channel connected'); // TODO: Make each task a channel for better use of the prefetch ch.prefetch(parseInt(process.env.TASKS_PREFETCH, 10) || 1); /* Send message to exchange abstraction */ const send = (exchange, routeKey, message, options = {}) => { let apmTransaction = false; if (apm) apmTransaction = apm.startTransaction(`${exchange} - ${routeKey}`, 'Rabbit'); // Check if it's an object, if true convert to json const parsedMsg = (typeof message === 'object' && !Array.isArray(message)) ? JSON.stringify(message) : message; ch.assertExchange(exchange, options.type || 'direct', { durable: true }); // Sends the message to the queue const status = ch.publish(exchange, routeKey, Buffer.from(parsedMsg)); if (apmTransaction) apmTransaction.end(); return status; }; /* Listen to messages in the queue abstraction */ const job = (exchange, routeKey, queue, prefetch, callback, options = {}) => { // Assert that this exchange exists ch.assertExchange(exchange, options.type || 'direct', { durable: true }); // Assert that the queue exists ch.assertQueue(queue); // Bind the queue in the exchange by the routing key ch.bindQueue(queue, exchange, routeKey); // prefetch if (prefetch) { ch.prefetch(prefetch); } // Consumes it ch.consume(queue, (msg) => { let apmTransaction = false; // Check if APM is enabled to track the transaction if (apm) apmTransaction = apm.startTransaction(queue, 'Rabbit'); // Lets threat the message const stringMsg = msg.content.toString(); let parsedMsg; // Tries to parse to object try { parsedMsg = JSON.parse(stringMsg); } catch (e) { // If it fails send as a string parsedMsg = stringMsg; } /** * We send back to the user only a callback with the payload content and a done fuction * so he can ack the message and possibly end the transaction. * @return {type} Description. */ callback(parsedMsg, (nack, requeue = true, allUpTo = false) => { // Check if APM is enabled to end the trasaction treacking if (apmTransaction) apmTransaction.end(); if (typeof nack !== 'undefined') { ch.nack(msg, allUpTo, requeue); return; } // Sends the acknolage to the message at Rabbit ch.ack(msg); }); }); }; resolve({ send, job, }); }); }); }) );