UNPKG

@bgaldino/nestjs-rabbitmq

Version:

A different way of configuring your RabbitMQ

200 lines 10.9 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var AMQPConnectionManager_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.AMQPConnectionManager = void 0; const common_1 = require("@nestjs/common"); const amqp_connection_manager_1 = require("amqp-connection-manager"); const node_os_1 = require("node:os"); const rabbitmq_consumers_1 = require("./rabbitmq-consumers"); const helper_1 = require("./helper"); let AMQPConnectionManager = AMQPConnectionManager_1 = class AMQPConnectionManager { constructor(options) { var _a, _b; this.rabbitTerminalErrors = [ "channel-error", "precondition-failed", "not-allowed", "access-refused", "closed via management plugin", ]; this.defaultOptions = { extraOptions: { logType: "none", consumerManualLoad: false, heartbeatIntervalInSeconds: 0, reconnectTimeInSeconds: 5, }, }; this.consumers = []; AMQPConnectionManager_1.rabbitModuleOptions = (0, helper_1.merge)(this.defaultOptions, options.createRabbitOptions()); this.logger = (_b = (_a = AMQPConnectionManager_1.rabbitModuleOptions.extraOptions) === null || _a === void 0 ? void 0 : _a.loggerInstance) !== null && _b !== void 0 ? _b : new common_1.Logger(AMQPConnectionManager_1.name); } async onModuleInit() { return this.connect(); } async onApplicationBootstrap() { if (AMQPConnectionManager_1.rabbitModuleOptions.extraOptions.consumerManualLoad) return; await this.createConsumers(); this.logger.debug("Initiating RabbitMQ consumers automatically"); } async onApplicationShutdown() { var _a, _b; this.logger.log("Closing RabbitMQ Connection"); await ((_a = AMQPConnectionManager_1 === null || AMQPConnectionManager_1 === void 0 ? void 0 : AMQPConnectionManager_1.consumerConn) === null || _a === void 0 ? void 0 : _a.close()); await ((_b = AMQPConnectionManager_1 === null || AMQPConnectionManager_1 === void 0 ? void 0 : AMQPConnectionManager_1.publisherConn) === null || _b === void 0 ? void 0 : _b.close()); } getConsumers() { return this.consumers; } async connect() { var _a, _b; const params = { heartbeatIntervalInSeconds: AMQPConnectionManager_1.rabbitModuleOptions.extraOptions .heartbeatIntervalInSeconds, reconnectTimeInSeconds: AMQPConnectionManager_1.rabbitModuleOptions.extraOptions .reconnectTimeInSeconds, connectionOptions: { keepAlive: true, keepAliveDelay: 5000, servername: (0, node_os_1.hostname)(), clientProperties: { connection_name: `${(_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.npm_package_name) !== null && _b !== void 0 ? _b : process.env.SERVICE_NAME}-${(0, node_os_1.hostname)()}-consumer`, }, }, }; await new Promise((resolve) => { var _a, _b; AMQPConnectionManager_1.consumerConn = (0, amqp_connection_manager_1.connect)(AMQPConnectionManager_1.rabbitModuleOptions.connectionString, Object.assign(Object.assign({}, params), { connectionOptions: { clientProperties: { connection_name: `${(_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.npm_package_name) !== null && _b !== void 0 ? _b : process.env.SERVICE_NAME}-${(0, node_os_1.hostname)()}-consumer`, }, } })); this.attachEvents("consumer", resolve); }); await new Promise((resolve) => { var _a, _b; AMQPConnectionManager_1.publisherConn = (0, amqp_connection_manager_1.connect)(AMQPConnectionManager_1.rabbitModuleOptions.connectionString, Object.assign(Object.assign({}, params), { connectionOptions: { clientProperties: { connection_name: `${(_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.npm_package_name) !== null && _b !== void 0 ? _b : process.env.SERVICE_NAME}-${(0, node_os_1.hostname)()}-publisher`, }, } })); this.attachEvents("publisher", resolve); }); await this.assertExchanges(); } attachEvents(type, resolve) { const conn = this.getConnection(type); conn.on("connect", async ({ url }) => { this.logger.log(`Rabbit ${type} connected to ${url.replace(new RegExp(url.replace(/amqp:\/\/[^:]*:([^@]*)@.*?$/i, "$1"), "g"), "***")}`); resolve(true); }); conn.on("disconnect", ({ err }) => { this.logger.warn(`Disconnected from rabbitmq: ${err.message}`); if (this.rabbitTerminalErrors.some((errorMessage) => err.message.toLowerCase().includes(errorMessage))) { conn.close(); this.logger.error({ message: `RabbitMQ Disconnected with a terminal error, impossible to reconnect `, error: err, x: err.message, }); } }); conn.on("connectFailed", ({ err }) => { this.logger.error(`Failure to connect to RabbitMQ instance: ${err.message}`); }); if (type === "publisher") { conn.on("blocked", ({ reason }) => { this.logger.error(`RabbitMQ broker is blocked with reason: ${reason}`); this.connectionBlockedReason = reason; }); conn.on("unblocked", () => { this.logger.error(`RabbitMQ broker connection is unblocked, last reason was: ${this.connectionBlockedReason}`); }); } } getConnection(type) { if (type === "publisher") { return AMQPConnectionManager_1.publisherConn; } else { return AMQPConnectionManager_1.consumerConn; } } async assertExchanges() { var _a, _b; await new Promise((resolve) => { AMQPConnectionManager_1.publishChannelWrapper = this.getConnection("publisher").createChannel({ name: `${process.env.npm_package_name}_publish`, confirm: true, publishTimeout: 60000, }); AMQPConnectionManager_1.publishChannelWrapper.on("connect", () => { this.logger.debug("Initiating RabbitMQ producers"); resolve(true); }); AMQPConnectionManager_1.publishChannelWrapper.on("close", () => { this.logger.debug("Closing RabbitMQ producer channel"); }); AMQPConnectionManager_1.publishChannelWrapper.on("error", (err, info) => { this.logger.error("Cannot open publish channel", err, info); }); }); for (const publisher of (_b = (_a = AMQPConnectionManager_1.rabbitModuleOptions) === null || _a === void 0 ? void 0 : _a.assertExchanges) !== null && _b !== void 0 ? _b : []) { await AMQPConnectionManager_1.publishChannelWrapper.addSetup(async (channel) => { var _a, _b, _c, _d, _e, _f; const isDelayed = (_b = (_a = publisher.options) === null || _a === void 0 ? void 0 : _a.isDelayed) !== null && _b !== void 0 ? _b : false; const type = isDelayed ? "x-delayed-message" : publisher.type; const argument = isDelayed ? { arguments: { "x-delayed-type": publisher.type } } : null; await channel.assertExchange(publisher.name, type, Object.assign({ durable: (_d = (_c = publisher === null || publisher === void 0 ? void 0 : publisher.options) === null || _c === void 0 ? void 0 : _c.durable) !== null && _d !== void 0 ? _d : true, autoDelete: (_f = (_e = publisher === null || publisher === void 0 ? void 0 : publisher.options) === null || _e === void 0 ? void 0 : _e.autoDelete) !== null && _f !== void 0 ? _f : false }, argument)); }); } } async createConsumers() { var _a; const consumerList = (_a = AMQPConnectionManager_1.rabbitModuleOptions.consumerChannels) !== null && _a !== void 0 ? _a : []; this.checkDuplicatedQueues(consumerList); for (const consumerEntry of consumerList) { const consumer = consumerEntry.options; this.consumers.push(await new rabbitmq_consumers_1.RabbitMQConsumer(AMQPConnectionManager_1.consumerConn, AMQPConnectionManager_1.rabbitModuleOptions, AMQPConnectionManager_1.publishChannelWrapper).createConsumer(consumer, consumerEntry.messageHandler)); } AMQPConnectionManager_1.isConsumersLoaded = true; } checkDuplicatedQueues(consumerList) { const queueNameList = []; consumerList.map((curr) => queueNameList.push(curr.options.queue)); const dedupList = new Set(queueNameList); if (dedupList.size != queueNameList.length) { this.logger.error({ error: "duplicated_queues", description: "Cannot have multiple queues on different binds", queues: Array.from(new Set(queueNameList.filter((value, index) => queueNameList.indexOf(value) != index))), }); process.exit(-1); } } }; exports.AMQPConnectionManager = AMQPConnectionManager; AMQPConnectionManager.publishChannelWrapper = null; AMQPConnectionManager.isConsumersLoaded = false; exports.AMQPConnectionManager = AMQPConnectionManager = AMQPConnectionManager_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)("RABBIT_OPTIONS")), __metadata("design:paramtypes", [Object]) ], AMQPConnectionManager); //# sourceMappingURL=amqp-connection-manager.js.map