UNPKG

pink-bears

Version:

Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications

132 lines (118 loc) 4.75 kB
const Axios = require('axios') const amqp = require('amqp-connection-manager'); const { emitEvent: emit } = require('./errorEmitter'); const { errorConstants } = require('./constants'); const { v4: uuidv4 } = require('uuid'); class Event { constructor({logger, domain, rabbitMQurl, rabbitMQExchange, rabbitMQRoutingKey, heartbeatIntervalInSeconds}) { this.domain = domain; this.rabbitMQurl = rabbitMQurl; this.rabbitMQExchange = rabbitMQExchange; this.rabbitMQRoutingKey = rabbitMQRoutingKey; this.logger = logger || console this.heartbeatIntervalInSeconds = heartbeatIntervalInSeconds || 60; this.connection = null; this.channel = null; this.flag = false; } createConnection() { this.connection = amqp.connect([this.rabbitMQurl], { heartbeatIntervalInSeconds: this.heartbeatIntervalInSeconds }); this.createChannel(this.connection); } createChannel(connection){ this.channel = connection.createChannel({ json: true, setup: () => { // No need to assert exchange and queue since they already exist }, }); } isConnectionAvailable(){ this.flag = this.connection.isConnected() return this.flag; } async getConnection() { if (this.connection !== null && this.channel !== null) { return true; } try{ if(this.connection){ this.createChannel(this.connection); return true; } this.createConnection(); return true; }catch(error){ await emit(errorConstants.event, error); this.logger.error("error occured while creating channel...", error); return false; } } async call(productEvent) { if(!productEvent?.traceId){ productEvent.traceId = uuidv4(); } try { if(this.isConnectionAvailable()){ this.logger.info(`Sending the payload with traceID ${productEvent.traceId} via rabbitMQ`); try { const isPublishedPromise = new Promise((resolve, reject) => { this.channel.publish(this.rabbitMQExchange, this.rabbitMQRoutingKey, productEvent, { contentType: 'application/json', persistent: true }, function(err, ok){ if (err !== null) { reject(err); } else { resolve(ok); } }); }); const isPublished = await Promise.race([ isPublishedPromise, new Promise((_, reject) => setTimeout(() => reject(new Error('Publish timeout')), 5000)), ]); if(!isPublished) throw new Error('Error while publishing'); } catch (error) { this.logger.error(`error while pushing to rabbitMQ for traceID ${productEvent.traceId}, hence trying with API call`, error) await Axios.post(`${this.domain}/api/sparrow-apps/event-listener`, productEvent); } }else{ this.logger.info(`connection not available to send messages via queue, hence retrying with api call for the traceID : ${productEvent.traceId}`); await Axios.post(`${this.domain}/api/sparrow-apps/event-listener`, productEvent); } return { success: true }; } catch (error) { await emit(errorConstants.event, error); this.logger.error(`Error occurred while sending message for traceID : ${productEvent.traceId}`, error); throw error; } } closeConnection() { this.channel.close(); this.connection.close(); } emitEvent = async (event, userId, productName, payload, queueEnabled) => { const dispatchData = { "Event": event, "userId": userId, "productName": productName, "payload": payload } try{ if(queueEnabled){ return await this.call(dispatchData); } else{ return await Axios.post(`${this.domain}/api/sparrow-apps/event-listener`, dispatchData); } } catch(error){ await emit(errorConstants.event, error); this.logger.error("Error while pushing to sparrow apps", error); throw error; } } } module.exports = Event;