@autofleet/rabbit 3.2.2-2.beta-0 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,19 +1,16 @@
1
1
  /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars */
2
2
 
3
- import { EventEmitter, once } from 'events';
3
+ import { EventEmitter } from 'events';
4
4
  import { promisify } from 'util';
5
5
  import moment from 'moment';
6
6
  import RedisLock from 'redis-lock';
7
- import {
8
- AmqpConnectionManager, ChannelWrapper, connect, CreateChannelOpts,
9
- } from 'amqp-connection-manager';
7
+ import { AmqpConnectionManager, ChannelWrapper, connect } from 'amqp-connection-manager';
10
8
  import {
11
9
  ConfirmChannel, ConsumeMessage, Options, Replies,
12
10
  } from 'amqplib';
13
11
  import {
14
12
  getCurrentPayload, newTrace, traceTypes, createOrSetRabbitTrace, outbreak,
15
13
  } from '@autofleet/zehut';
16
- import { randomUUID } from 'node:crypto';
17
14
  import logger from './logger';
18
15
  import RabbitError from './lib/rabbitError';
19
16
  import getRedisInstance, { RedisConfig } from './lib/redis';
@@ -35,15 +32,14 @@ import {
35
32
  CustomMessageHeaders,
36
33
  QueuesCache,
37
34
  RedisLockType,
38
- ExchangesCache, CONSUMER_DEFAULT_OPTIONS, QueueSetupPromisesDictionary,
39
- ConnectionPurpose,
40
- ConnectionData,
35
+ ExchangesCache, CONSUMER_DEFAULT_OPTIONS,
41
36
  } from './lib/types';
42
37
 
43
38
  // const debug = nodeDebug('af-rabbitmq')
44
- const debug = logger.debug.bind(logger);
39
+ const debug = logger.info;
45
40
 
46
41
  const PUBLISH_TIMEOUT = 1000 * 10;
42
+
47
43
  export interface IAfRabbitMq {
48
44
  ack: any;
49
45
  nack: any;
@@ -57,10 +53,6 @@ export interface IAfRabbitMq {
57
53
  redisClient?: any;
58
54
  }
59
55
 
60
- interface NackOptions {
61
- skipRetry?: boolean;
62
- }
63
-
64
56
  export interface AfRabbitOptions {
65
57
  disableReconnect?: boolean;
66
58
 
@@ -82,14 +74,11 @@ export interface AfRabbitOptions {
82
74
  type newChannelOpts = {
83
75
  name?: string;
84
76
  onClose?: null | ((args: any | null) => void);
85
- options?: CreateChannelOpts | undefined;
86
- connectionPurpose: ConnectionPurpose,
87
77
  };
88
78
 
89
79
  type assertChannelOpts = {
90
80
  channelName?: string;
91
81
  force?: boolean;
92
- connectionPurpose: ConnectionPurpose;
93
82
  }
94
83
 
95
84
  type AfConsumer = {
@@ -101,7 +90,7 @@ type AfConsumer = {
101
90
  const HEARTBEAT = '60';
102
91
 
103
92
  class RabbitMq implements IAfRabbitMq {
104
- static parseMsg(msg: any): any {
93
+ static parseMsg(msg: any) : any {
105
94
  let { content } = msg;
106
95
  content = content.toString();
107
96
 
@@ -115,7 +104,7 @@ class RabbitMq implements IAfRabbitMq {
115
104
  };
116
105
  }
117
106
 
118
- static validateName(type: string, name: string): void {
107
+ static validateName(type: string, name: string) {
119
108
  if (!name || name === '') {
120
109
  throw new RabbitError(`error while using ${type} with no name`);
121
110
  }
@@ -144,23 +133,18 @@ class RabbitMq implements IAfRabbitMq {
144
133
 
145
134
  channel: ChannelWrapper | null;
146
135
 
147
- publishChannelSetupPromise: Promise<ChannelWrapper> | null;
148
-
149
- blockReconnect: boolean | null | undefined;
136
+ blockReconnect: boolean | null | undefined
150
137
 
151
- connectionsMap: {
152
- [ConnectionPurpose.Consume]: ConnectionData;
153
- [ConnectionPurpose.Publish]: ConnectionData;
154
- };
138
+ connection: AmqpConnectionManager | null | undefined
155
139
 
156
140
  em: EventEmitter;
157
141
 
142
+ creatingConnection: boolean;
143
+
158
144
  exchanges: ExchangesCache;
159
145
 
160
146
  queues: QueuesCache;
161
147
 
162
- queueSetupPromises: QueueSetupPromisesDictionary;
163
-
164
148
  options: AfRabbitOptions | undefined;
165
149
 
166
150
  redisClient: any;
@@ -175,15 +159,10 @@ class RabbitMq implements IAfRabbitMq {
175
159
  constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig) {
176
160
  this.em = new EventEmitter();
177
161
  this.channel = null;
178
- this.publishChannelSetupPromise = null;
179
- this.connectionsMap = {
180
- [ConnectionPurpose.Consume]: { connection: null, creatingConnection: false },
181
- [ConnectionPurpose.Publish]: { connection: null, creatingConnection: false },
182
- };
162
+ this.connection = null;
163
+ this.creatingConnection = false;
183
164
  this.exchanges = {};
184
165
  this.queues = {};
185
- this.queueSetupPromises = {};
186
- this.consumers = [];
187
166
  this.options = options;
188
167
  this.redisClient = redisConfig && getRedisInstance(redisConfig);
189
168
  if (this.redisClient) {
@@ -215,9 +194,8 @@ class RabbitMq implements IAfRabbitMq {
215
194
  return false;
216
195
  }
217
196
 
218
- public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage): Promise<any> => {
197
+ public ack = (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
219
198
  if (msg) {
220
- debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
221
199
  await channel.ack(msg);
222
200
  const { properties: { headers } } = msg;
223
201
  const timestamp = headers?.creationTimestamp;
@@ -231,7 +209,7 @@ class RabbitMq implements IAfRabbitMq {
231
209
  }
232
210
 
233
211
  public nack = (
234
- channel: ConfirmChannel,
212
+ channel: ChannelWrapper,
235
213
  queue: string,
236
214
  options: any,
237
215
  deadQueueOptions: Options.AssertQueue,
@@ -241,8 +219,8 @@ class RabbitMq implements IAfRabbitMq {
241
219
  userMsg: ConsumeMessageOrNull,
242
220
  {
243
221
  skipRetry = false,
244
- }: NackOptions = {},
245
- ): Promise<any> => {
222
+ }: any = { },
223
+ ) : Promise<any> => {
246
224
  await this.unlockRedisIfNeeded(releaseLock);
247
225
  if (channel && msg) {
248
226
  if (
@@ -267,45 +245,41 @@ class RabbitMq implements IAfRabbitMq {
267
245
  : 1,
268
246
  });
269
247
  }
270
- debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
271
248
  await channel.ack(msg);
272
249
  } else {
273
250
  logger.error('no channel or msg', {
251
+ channel: channel ? channel.name : '',
274
252
  msg,
275
253
  });
276
254
  }
277
255
  }
278
256
 
279
- async getConnection(connectionPurpose: ConnectionPurpose) {
280
- return new Promise<AmqpConnectionManager | undefined | null>(async (resolve, reject) => {
281
- let { connection, creatingConnection } = this.connectionsMap[connectionPurpose];
257
+ async getConnection() {
258
+ return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
282
259
  if (this.blockReconnect) {
283
260
  debug('rabbit: block reconnect');
284
261
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
285
262
  // @ts-ignore
286
263
  return resolve();
287
264
  }
288
- if (connection !== null) {
289
- if (this.options?.disableReconnect || connection?.isConnected()) {
265
+ if (this.connection !== null) {
266
+ if (this.options?.disableReconnect || this.connection?.isConnected()) {
290
267
  debug('rabbit: connection - is connected');
291
268
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
292
269
  // @ts-ignore
293
- return resolve(connection);
270
+ return resolve(this.connection);
294
271
  }
295
272
  debug('rabbit: connection - reconnecting');
296
273
  }
297
- if (creatingConnection) {
274
+ if (this.creatingConnection) {
298
275
  debug('rabbit: creating connection emi');
299
276
  this.em.once(CONNECTION_CREATED_CONST, resolve);
300
277
  this.em.once(CONNECTION_FAILED_CONST, reject);
301
278
  return;
302
279
  }
303
- this.connectionsMap[connectionPurpose].creatingConnection = true;
280
+ this.creatingConnection = true;
304
281
  let isResolved = false;
305
282
 
306
- // It is import to use it as a function and not as a variable
307
- // because of k8s changes the env variables
308
- // and we want to use the new values
309
283
  const findServers = () => {
310
284
  const userName = process.env.RABBITMQ_USERNAME || 'guest';
311
285
  const password = process.env.RABBITMQ_PASSWORD || 'guest';
@@ -317,18 +291,12 @@ class RabbitMq implements IAfRabbitMq {
317
291
  };
318
292
 
319
293
  const defaultUrls = findServers();
320
- const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
294
+ const connection: AmqpConnectionManager = await connect(defaultUrls, {
321
295
  findServers,
322
296
  });
323
297
 
324
- if (!newConnection) {
325
- logger.error('rabbit: couldnt create a connection');
326
- return resolve(connection);
327
- }
328
-
329
- this.connectionsMap[connectionPurpose].connection = newConnection;
330
-
331
- newConnection.on('error', (err) => {
298
+ this.connection = connection;
299
+ this.connection.on('error', (err) => {
332
300
  logger.error('rabbit: connection error', { err });
333
301
  if (!isResolved) {
334
302
  isResolved = true;
@@ -337,8 +305,7 @@ class RabbitMq implements IAfRabbitMq {
337
305
  }
338
306
  });
339
307
 
340
- newConnection.on('connectFailed', (err) => {
341
- this.consumersTags = [];
308
+ this.connection.on('connectFailed', (err) => {
342
309
  logger.error('rabbit: connection connectFailed', { err });
343
310
  if (!isResolved) {
344
311
  isResolved = true;
@@ -347,9 +314,10 @@ class RabbitMq implements IAfRabbitMq {
347
314
  }
348
315
  });
349
316
 
350
- newConnection.on('disconnect', ({ err }) => {
351
- this.consumersTags = [];
317
+ this.connection.on('disconnect', ({ err }) => {
352
318
  debug('rabbit: connection closed');
319
+ this.exchanges = {};
320
+ this.queues = {};
353
321
  if (this.options?.disableReconnect) {
354
322
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
355
323
  this.blockReconnect = true;
@@ -357,68 +325,67 @@ class RabbitMq implements IAfRabbitMq {
357
325
  logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
358
326
  }
359
327
  });
360
- newConnection.once('connect', async () => {
328
+ this.connection.once('connect', async () => {
361
329
  debug('rabbit: connection established');
362
- this.connectionsMap[connectionPurpose].creatingConnection = false;
363
- this.em.emit(CONNECTION_CREATED_CONST, newConnection);
330
+ await this.loadConsumers();
331
+ this.creatingConnection = false;
332
+ this.em.emit(CONNECTION_CREATED_CONST, connection);
364
333
  isResolved = true;
365
- resolve(newConnection);
334
+ resolve(connection);
366
335
  });
367
336
  });
368
337
  }
369
338
 
370
- async getNewChannel({
371
- name = rand().toString(), onClose = null, options = {}, connectionPurpose = ConnectionPurpose.Consume,
372
- }: newChannelOpts): Promise<ChannelWrapper> {
373
- let connection!: AmqpConnectionManager | undefined | null;
374
- try {
375
- connection = await this.getConnection(connectionPurpose);
376
- } catch (e) {
377
- logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
378
- throw e;
379
- }
380
- if (!connection) {
381
- throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
382
- }
383
- const channel = connection.createChannel({ ...options });
384
- once(channel, 'close').then((args) => {
385
- logger.error(`rabbit: channel ${name} closed`);
386
- onClose?.(args);
387
- });
388
- try {
389
- await once(channel, 'connect');
390
- debug(`rabbit: channel ${name} CONNECTED`);
391
- return channel;
392
- } catch (err) {
393
- logger.error(`rabbit: channel error ${name} error`, { err });
394
- throw err;
395
- }
396
- }
339
+ async getNewChannel({ name = rand().toString(), onClose = null }: newChannelOpts = {}) {
340
+ return new Promise<ChannelWrapper>(async (resolve, reject) => {
341
+ const connection: AmqpConnectionManager = await this.getConnection();
342
+ const channel = connection.createChannel({
343
+ });
397
344
 
398
- async assertChannel({ force = false, connectionPurpose = ConnectionPurpose.Consume }: assertChannelOpts): Promise<ChannelWrapper> {
399
- if (!this.publishChannelSetupPromise) {
400
- this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
401
- if (this.channel && !force) {
402
- return resolve(this.channel);
345
+ let isResolved = false;
346
+ channel.on('error', (err) => {
347
+ logger.error(`rabbit: channel ${name} error`, { err });
348
+ if (!isResolved) {
349
+ isResolved = true;
350
+ reject(err);
403
351
  }
404
-
405
- try {
406
- const channel = await this.getNewChannel({ connectionPurpose });
407
- channel.on('error', (err) => {
408
- logger.error('rabbit: channel error', { err });
409
- });
410
- this.channel = channel;
411
- resolve(channel);
412
- } catch (e) {
413
- reject(e);
352
+ });
353
+ channel.on('close', (...args) => {
354
+ logger.error(`rabbit: channel ${name} closed`, { args });
355
+ if (onClose) {
356
+ onClose(args);
414
357
  }
415
358
  });
416
- }
417
- return this.publishChannelSetupPromise;
359
+ channel.once('connect', () => {
360
+ debug(`rabbit: channel ${name} CONNECTED`);
361
+ isResolved = true;
362
+ resolve(channel);
363
+ });
364
+ });
365
+ }
366
+
367
+ async assertChannel({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
368
+ return new Promise<ChannelWrapper>(async (resolve, reject) => {
369
+ if (this.channel && !force) {
370
+ return resolve(this.channel);
371
+ }
372
+
373
+ try {
374
+ const channel = await this.getNewChannel({
375
+ });
376
+ channel.on('error', (err) => {
377
+ logger.error('rabbit: channel error', { err });
378
+ });
379
+ this.channel = channel;
380
+ resolve(channel);
381
+ } catch (e) {
382
+ reject(e);
383
+ }
384
+ });
418
385
  }
419
386
 
420
387
  async assertExchange(exchangeName: string, options?: any) {
421
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: options.connectionPurpose });
388
+ const channel: ChannelWrapper = await this.assertChannel();
422
389
  if (this.exchanges[exchangeName]) {
423
390
  return this.exchanges[exchangeName];
424
391
  }
@@ -427,36 +394,36 @@ class RabbitMq implements IAfRabbitMq {
427
394
  return exchange;
428
395
  }
429
396
 
430
- async getQueueLength(queue: string, connectionPurpose: ConnectionPurpose = ConnectionPurpose.Consume): Promise<Replies.AssertQueue> {
397
+ async getQueueLength(queue: string) {
431
398
  RabbitMq.validateName('queue', queue);
432
- let { connection } = this.connectionsMap[connectionPurpose];
433
- const { channel } = this;
434
- if (!channel) {
435
- throw new Error('channel is not defined');
436
- }
437
- debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
438
- return channel?.checkQueue(queue);
399
+ const channel: ChannelWrapper = await this.assertChannel();
400
+ debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
401
+ return channel.checkQueue(queue);
439
402
  }
440
403
 
441
- private async deleteQueue(queue: string, connectionPurpose: ConnectionPurpose) {
404
+ private async deleteQueue(queue: string) {
442
405
  RabbitMq.validateName('queue', queue);
443
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
406
+ const channel: ChannelWrapper = await this.assertChannel();
444
407
  logger.info('rabbit: deleting queue', { queue });
445
408
  const deleteQueueRes = await channel.deleteQueue(queue);
446
409
  debug('queue deleted', deleteQueueRes);
447
410
  return deleteQueueRes;
448
411
  }
449
412
 
450
- async bindQueue(queue: string, exchange: string, connectionPurpose: ConnectionPurpose) {
451
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
413
+ async bindQueue(queue: string, exchange: string) {
414
+ const channel: ChannelWrapper = await this.assertChannel();
452
415
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
453
416
  return channel.bindQueue(queue, exchange, '');
454
417
  }
455
418
 
456
- async setupQueue(queueName: string, connectionPurpose: ConnectionPurpose, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
457
- let queue: Replies.AssertQueue;
419
+ async assertQueue(queueName: string, options?: Options.AssertQueue) {
420
+ let queue: Replies.AssertQueue | null = null;
421
+ RabbitMq.validateName('queue', queueName);
422
+ if (this.queues[queueName]) {
423
+ return this.queues[queueName];
424
+ }
458
425
  try {
459
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
426
+ const channel: ChannelWrapper = await this.assertChannel();
460
427
  debug('assertQueue->channel.addSetup', { queueName });
461
428
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
462
429
  debug('assertQueue->channel.assertQueue', { queueName });
@@ -465,12 +432,12 @@ class RabbitMq implements IAfRabbitMq {
465
432
  logger.error('rabbit: assertQueue error', { queueName, options, error: e });
466
433
  if (!this.options?.dontRetryAssert) {
467
434
  debug('retrying assertQueue', { queueName });
468
- const channel = await this.assertChannel({ force: true, connectionPurpose });
469
- await this.deleteQueue(queueName, connectionPurpose);
435
+ const channel = await this.assertChannel({ force: true });
436
+ await this.deleteQueue(queueName);
470
437
 
471
- debug('retrying assertQueue->channel.addSetup', { queueName });
438
+ debug('1assertQueue->channel.addSetup', { queueName });
472
439
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
473
- debug('retrying assertQueue->channel.assertQueue', { queueName });
440
+ debug('1assertQueue->channel.assertQueue', { queueName });
474
441
  queue = await channel.assertQueue(queueName, options);
475
442
  } else {
476
443
  throw e;
@@ -481,35 +448,29 @@ class RabbitMq implements IAfRabbitMq {
481
448
  return queue;
482
449
  }
483
450
 
484
- async assertQueue(queueName: string, connectionPurpose: ConnectionPurpose, options?: Options.AssertQueue) {
485
- RabbitMq.validateName('queue', queueName);
486
- if (this.queues[queueName]) {
487
- delete this.queueSetupPromises[queueName];
488
- return this.queues[queueName];
489
- }
490
-
491
- if (this.queueSetupPromises[queueName]) {
492
- return this.queueSetupPromises[queueName];
493
- }
494
-
495
- this.queueSetupPromises[queueName] = this.setupQueue(queueName, connectionPurpose, options);
496
- return this.queueSetupPromises[queueName];
451
+ private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
452
+ this.consumers.push({
453
+ queue,
454
+ callback,
455
+ options,
456
+ });
497
457
  }
498
458
 
499
- private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
500
- const isConsumerExist: boolean = this.consumers.some((consumer) => consumer.queue === queue);
501
- if (!isConsumerExist) {
502
- logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
503
- this.consumers.push({
504
- queue,
505
- callback,
506
- options,
507
- });
459
+ private async loadConsumers() {
460
+ debug('rabbit: loading consumers', { consumers: this.consumers.length });
461
+ if (this.consumers.length > 0) {
462
+ await Promise.all(
463
+ this.consumers.map((consumer) => this
464
+ .consumeFromRabbit(consumer.queue, consumer.callback, consumer.options)),
465
+ );
508
466
  }
509
467
  }
510
468
 
511
469
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
512
- await this.consumeFromRabbit(queue, callback, options);
470
+ if (this.connection && !this.creatingConnection) {
471
+ this.consumeFromRabbit(queue, callback, options);
472
+ }
473
+ return this.saveConsumer(queue, callback, options);
513
474
  }
514
475
 
515
476
  private async lockRedisIfNeeded(msg: any, options: any) {
@@ -535,8 +496,6 @@ class RabbitMq implements IAfRabbitMq {
535
496
  private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
536
497
  const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
537
498
  RabbitMq.validateName('queue', queue);
538
- this.saveConsumer(queue, callback, options);
539
- const uniqueId = randomUUID();
540
499
  const {
541
500
  limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace,
542
501
  } = optionsWithDefaults;
@@ -546,11 +505,11 @@ class RabbitMq implements IAfRabbitMq {
546
505
  }
547
506
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
548
507
  }
549
- const channel = await this.getNewChannel({ connectionPurpose: ConnectionPurpose.Consume });
550
- return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
551
- await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
552
- await confirmChannel.prefetch(limit, true);
553
- const { consumerTag } = await confirmChannel.consume(
508
+ const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-queue-${queue}` });
509
+ return channel.addSetup(async (c: ConfirmChannel) => {
510
+ await c.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
511
+ await c.prefetch(limit, true);
512
+ const { consumerTag } = await c.consume(
554
513
  queue,
555
514
  async (msg: ConsumeMessageOrNull) => {
556
515
  if (!msg) {
@@ -574,7 +533,7 @@ class RabbitMq implements IAfRabbitMq {
574
533
  ]);
575
534
  } catch (e) {
576
535
  logger.error('rabbit: failed to setRabbitTrace', { userId, e });
577
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
536
+ await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
578
537
  }
579
538
  }
580
539
 
@@ -589,37 +548,16 @@ class RabbitMq implements IAfRabbitMq {
589
548
  const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
590
549
  if (!shouldConsume) {
591
550
  await this.unlockRedisIfNeeded(releaseLock);
592
- return this.ack(confirmChannel, msg)(msg);
551
+ return this.ack(channel, msg)(msg);
593
552
  }
594
-
595
- let messageAcked = false;
596
- // setting the localAck function to be used in the callback
597
-
598
- const localAck = async () => {
599
- if (messageAcked) {
600
- return;
601
- }
602
- messageAcked = true;
603
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
604
- };
605
-
606
- const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
607
- if (messageAcked) {
608
- return;
609
- }
610
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
611
- messageAcked = true;
612
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
613
- };
614
-
615
553
  try {
616
554
  await callback(
617
555
  parsedMessage,
618
- localAck,
619
- localNack,
556
+ this.ack(channel, msg, true, releaseLock),
557
+ this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock),
620
558
  );
621
559
  } catch (e) {
622
- await localNack(msg);
560
+ await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
623
561
  }
624
562
  }, CONSUMER_DEFAULT_OPTIONS,
625
563
  );
@@ -627,18 +565,17 @@ class RabbitMq implements IAfRabbitMq {
627
565
  logger.error(`rabbit: failed to consume from queue ${queue}`);
628
566
  } else {
629
567
  logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
630
- this.consumersTags.push([confirmChannel, consumerTag]);
568
+ this.consumersTags.push([c, consumerTag]);
631
569
  }
632
570
  });
633
571
  }
634
572
 
635
- async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
573
+ async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
636
574
  const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
637
575
  RabbitMq.validateName('exchange', exchange);
638
576
  RabbitMq.validateName('queue', queue);
639
577
  const { limit, deadMessageTtl } = optionsWithDefaults;
640
- await this.saveConsumer(queue, callback, options);
641
- const channel: ChannelWrapper = await this.getNewChannel({ name: `consume - exchange - ${exchange} -queue - ${queue}`, connectionPurpose: ConnectionPurpose.Consume });
578
+ const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
642
579
 
643
580
  return channel.addSetup(async (c: ConfirmChannel) => {
644
581
  const assertExchange = await assertExchangeFanout(c, exchange);
@@ -656,11 +593,11 @@ class RabbitMq implements IAfRabbitMq {
656
593
  });
657
594
  }
658
595
 
659
- async publish(exchange: string, content: any, customHeaders?: any): Promise<boolean> {
596
+ async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
660
597
  return wrapSetImmediate(async () => {
661
598
  RabbitMq.validateName('exchange', exchange);
662
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
663
- await this.assertExchange(exchange, { connectionPurpose: ConnectionPurpose.Publish });
599
+ const channel: ChannelWrapper = await this.assertChannel();
600
+ await this.assertExchange(exchange);
664
601
  await channel.publish(exchange, '',
665
602
  Buffer.from(JSON.stringify(content)),
666
603
  RabbitMq.getPublishOptions(customHeaders));
@@ -672,61 +609,35 @@ class RabbitMq implements IAfRabbitMq {
672
609
  content: any,
673
610
  options?: any,
674
611
  customHeaders?: any,
612
+ isBlocking?: boolean,
675
613
  ): Promise<boolean | undefined> {
676
- try {
677
- await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
678
- } catch (e) {
679
- logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
680
- throw e;
681
- }
682
-
683
- try {
684
- RabbitMq.validateName('queue', queue);
685
- await this.assertQueue(queue, ConnectionPurpose.Publish, options);
686
- } catch (e) {
687
- logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
688
- throw e;
689
- }
690
-
691
- try {
692
- const res = await this.channel?.sendToQueue(queue,
693
- Buffer.from(JSON.stringify(content)),
694
- RabbitMq.getPublishOptions(customHeaders));
695
- debug(`rabbit: sending to queue ${queue}`, { res });
696
- return res;
697
- } catch (e) {
698
- const isConnected = await this.isConnected(ConnectionPurpose.Publish);
699
- logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
700
- throw e;
614
+ const callback = async (): Promise<boolean | undefined> => {
615
+ try {
616
+ RabbitMq.validateName('queue', queue);
617
+ await this.assertChannel();
618
+ await this.assertQueue(queue, options);
619
+ const res = await this.channel?.sendToQueue(queue,
620
+ Buffer.from(JSON.stringify(content)),
621
+ RabbitMq.getPublishOptions(customHeaders));
622
+ debug(`rabbit: sending to queue ${queue}`, { res });
623
+ return res;
624
+ } catch (e) {
625
+ logger.error(`rabbit: failed to send to queue ${queue}`, { e });
626
+ throw e;
627
+ }
628
+ };
629
+ if (isBlocking) {
630
+ return callback();
701
631
  }
632
+ return wrapSetImmediate(callback);
702
633
  }
703
634
 
704
- async isConnected(connectionPurpose: ConnectionPurpose): Promise<boolean> {
705
- const connection = await this.getConnection(connectionPurpose);
706
- if (!connection) {
707
- logger.error('rabbit: isConnected - false');
708
- return false;
709
- }
710
- const isConnected = connection.isConnected();
711
- if (!isConnected) {
712
- logger.error('rabbit: isConnected - false');
713
- return false;
714
- }
715
- const channel: any = await this.assertChannel({ connectionPurpose });
716
- try {
717
- await Promise.all([
718
- channel.waitForConnect(),
719
- ...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
720
- ]);
721
- } catch (e) {
722
- logger.error('rabbit: isConnected - false');
723
- return false;
724
- }
725
- logger.info('rabbit: isConnected - true');
726
- return true;
635
+ async isConnected() : Promise<boolean> {
636
+ const connection = await this.getConnection();
637
+ return connection.isConnected();
727
638
  }
728
639
 
729
- async gracefulShutdown(signal: string): Promise<void> {
640
+ async gracefulShutdown(signal: string) : Promise<void> {
730
641
  const tagsNumber = this.consumersTags.length;
731
642
  logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
732
643
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));