@jiaxinjiang/nest-amqp
Version:
RabbitMQ component for NestJs.
163 lines • 6.5 kB
JavaScript
"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