UNPKG

@suissa/universal-queues

Version:

Factory universal para mensageria (RabbitMQ, Kafka, SQS) para sistemas distribuĂ­dos.

130 lines (112 loc) • 3.63 kB
import amqplib, { ConsumeMessage } from 'amqplib'; import { IMessaging } from './interfaces/IMessaging'; import { Retry } from './decorators/retry'; interface RabbitClientOpts { prefetch?: number; } export class RabbitMQClient implements IMessaging { private connection!: any; private channel!: any; private prefetch: number = 1; constructor(opts: RabbitClientOpts = {}) { this.prefetch = opts.prefetch ?? 0; } async connect(uri: string) { this.connection = await amqplib.connect(uri); this.channel = await this.connection.createChannel(); if (this.prefetch > 0) { await this.channel.prefetch(this.prefetch); } const close = async () => { try { await this.close(); } catch {} process.exit(0); }; process.once('SIGINT', close); process.once('SIGTERM', close); } @Retry(3, 1000) async publishEvent( exchange: string, routingKey: string, message: object, headers: any = {} ) { await this.channel.assertExchange(exchange, 'topic', { durable: true }); this.channel.publish( exchange, routingKey, Buffer.from(JSON.stringify(message)), { headers, persistent: true } ); } async subscribeToEvent( exchange: string, queue: string, routingKey: string, handler: (msg: any) => void ) { await this.channel.assertExchange(exchange, 'topic', { durable: true }); await this.channel.assertQueue(queue, { durable: true, deadLetterExchange: `${exchange}.dlq` }); await this.channel.bindQueue(queue, exchange, routingKey); this.channel.consume(queue, (msg: ConsumeMessage | null) => { if (msg) { try { const content = JSON.parse(msg.content.toString()); handler(content); this.ackMessage(msg); } catch (err) { this.nackMessage(msg); } } }); } async publishToFanout(exchange: string, message: object) { await this.channel.assertExchange(exchange, 'fanout', { durable: true }); this.channel.publish(exchange, '', Buffer.from(JSON.stringify(message))); } async subscribeToFanout( exchange: string, handler: (msg: any) => void ) { await this.channel.assertExchange(exchange, 'fanout', { durable: true }); const q = await this.channel.assertQueue('', { exclusive: true }); await this.channel.bindQueue(q.queue, exchange, ''); this.channel.consume(q.queue, (msg: ConsumeMessage | null) => { if (msg) { handler(JSON.parse(msg.content.toString())); this.ackMessage(msg); } }); } async publishToOutbox(event: object) { console.log('[OUTBOX]', event); } async handleDeadLetter( dlqExchange: string, dlqQueue: string, handler: (msg: any) => void ) { await this.channel.assertExchange(dlqExchange, 'fanout', { durable: true }); await this.channel.assertQueue(dlqQueue, { durable: true }); await this.channel.bindQueue(dlqQueue, dlqExchange, ''); this.channel.consume(dlqQueue, (msg: ConsumeMessage | null) => { if (msg) { handler(JSON.parse(msg.content.toString())); this.ackMessage(msg); } }); } ackMessage(msg: ConsumeMessage) { this.channel.ack(msg); } nackMessage(msg: ConsumeMessage, requeue = false) { this.channel.nack(msg, false, requeue); } async close() { if (this.channel) await this.channel.close(); if (this.connection) await this.connection.close(); } }