UNPKG

@jiaxinjiang/nest-amqp

Version:

RabbitMQ component for NestJs.

163 lines 6.5 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 AmqpService_1; Object.defineProperty(exports, "__esModule", { value: true }); const amqplib_1 = require("amqplib"); const common_1 = require("@nestjs/common"); const core_1 = require("@nestjs/core"); const amqp_constants_1 = require("./amqp.constants"); function defaultDecode(data) { return JSON.parse(data.toString()); } let AmqpService = AmqpService_1 = class AmqpService { constructor(discoveryService, metadataScanner, reflector, amqpConfig) { this.discoveryService = discoveryService; this.metadataScanner = metadataScanner; this.reflector = reflector; this.amqpConfig = amqpConfig; this.needReconnect = true; this.logger = amqpConfig.logger || new common_1.Logger(AmqpService_1.name); } get connection() { return this._connection; } get channel() { return this._channel; } get config() { return this.amqpConfig; } async amqpInit() { await this.connect(); await this.createChannel(); } onApplicationBootstrap() { this.explore(); } async amqpDestroy() { this.needReconnect = false; if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = undefined; } if (this._connection) { try { await this._connection.close(); } catch (err) { } this._connection = null; } } async connect() { this._connection = await amqplib_1.connect(this.amqpConfig.connection); this._connection.once("close", this.onConnectionClose.bind(this)); this._connection.on("error", (err) => this.logger.error(err)); } async createChannel() { try { this._channel = await this._connection.createConfirmChannel(); this._channel.on("close", () => this.onChannelClose()); this._channel.on("error", (error) => this.onChannelError(error)); } catch (err) { setTimeout(() => { this.createChannel(); }, 1000); } } explore() { const providers = this.discoveryService.getProviders(); for (const wrapper of providers) { const { instance } = wrapper; if (instance) { this.initConsumer(instance); } } } initConsumer(instance) { this.metadataScanner.scanFromPrototype(instance, Object.getPrototypeOf(instance), async (key) => { const queueName = this.reflector.get(amqp_constants_1.AMQP_CONSUMER_METADATA, instance[key]); if (!queueName) { return; } const queueMetadata = this.amqpConfig.queues.find((option) => option.queue === queueName); const exchangeMetadate = this.amqpConfig.exchanges.find((option) => option.exchange === queueMetadata.exchange); const { exchange, type, options: exchangeOptions } = exchangeMetadate; const { nackOptions = {}, options: queueOptions, patterns, consume = {}, decode = defaultDecode, } = queueMetadata; await this._channel.assertExchange(exchange, type || "direct", exchangeOptions); const queue = await this._channel.assertQueue(queueName, queueOptions); if (exchangeMetadate.type !== "fanout") { if (patterns instanceof Array) { for (const pattern of patterns) { await this._channel.bindQueue(queue.queue, exchange, pattern); } } else { await this._channel.bindQueue(queue.queue, exchange, patterns); } } else { await this._channel.bindQueue(queue.queue, exchange, ""); } await this._channel.prefetch(1); await this._channel.consume(queue.queue, async (msg) => { this.logger.log(`Received AMQP Message: { Exchange: ${exchange}, Queue: ${queue.queue}, Function: ${instance[key].name} }`); try { await instance[key](decode(msg.content), msg.fields, msg.properties); this._channel.ack(msg); } catch (err) { this._channel.nack(msg, nackOptions.allUpTo, nackOptions.requeue); this.logger.error(err); } }, Object.assign({}, consume, { noAck: consume.noAck === true ? true : false })); this.logger.log(`[Consumer -> exchange: ${exchange} queue: ${queue.queue}] initialized`); }); } onConnectionClose() { if (this.needReconnect) { this.reconnectTimer = setTimeout(() => { this.reconnectTimer = undefined; this.amqpInit().catch(() => { this.onConnectionClose(); }); }, 3000); } } async closeChannel() { if (!this._channel) { return; } try { await this._channel.close(); } catch (err) { } this._channel = null; } async onChannelError(error) { error && this.logger.error(error); } async onChannelClose() { await this.closeChannel(); setTimeout(() => { this.createChannel(); }, 3000); } }; AmqpService = AmqpService_1 = __decorate([ common_1.Injectable(), __metadata("design:paramtypes", [core_1.DiscoveryService, core_1.MetadataScanner, core_1.Reflector, Object]) ], AmqpService); exports.AmqpService = AmqpService; //# sourceMappingURL=amqp.service.js.map