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

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,40 +245,39 @@ 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
283
  // It is import to use it as a function and not as a variable
@@ -317,18 +294,12 @@ class RabbitMq implements IAfRabbitMq {
317
294
  };
318
295
 
319
296
  const defaultUrls = findServers();
320
- const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
297
+ const connection: AmqpConnectionManager = await connect(defaultUrls, {
321
298
  findServers,
322
299
  });
323
300
 
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) => {
301
+ this.connection = connection;
302
+ this.connection.on('error', (err) => {
332
303
  logger.error('rabbit: connection error', { err });
333
304
  if (!isResolved) {
334
305
  isResolved = true;
@@ -337,8 +308,7 @@ class RabbitMq implements IAfRabbitMq {
337
308
  }
338
309
  });
339
310
 
340
- newConnection.on('connectFailed', (err) => {
341
- this.consumersTags = [];
311
+ this.connection.on('connectFailed', (err) => {
342
312
  logger.error('rabbit: connection connectFailed', { err });
343
313
  if (!isResolved) {
344
314
  isResolved = true;
@@ -347,9 +317,10 @@ class RabbitMq implements IAfRabbitMq {
347
317
  }
348
318
  });
349
319
 
350
- newConnection.on('disconnect', ({ err }) => {
351
- this.consumersTags = [];
320
+ this.connection.on('disconnect', ({ err }) => {
352
321
  debug('rabbit: connection closed');
322
+ this.exchanges = {};
323
+ this.queues = {};
353
324
  if (this.options?.disableReconnect) {
354
325
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
355
326
  this.blockReconnect = true;
@@ -357,68 +328,67 @@ class RabbitMq implements IAfRabbitMq {
357
328
  logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
358
329
  }
359
330
  });
360
- newConnection.once('connect', async () => {
331
+ this.connection.once('connect', async () => {
361
332
  debug('rabbit: connection established');
362
- this.connectionsMap[connectionPurpose].creatingConnection = false;
363
- this.em.emit(CONNECTION_CREATED_CONST, newConnection);
333
+ await this.loadConsumers();
334
+ this.creatingConnection = false;
335
+ this.em.emit(CONNECTION_CREATED_CONST, connection);
364
336
  isResolved = true;
365
- resolve(newConnection);
337
+ resolve(connection);
366
338
  });
367
339
  });
368
340
  }
369
341
 
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
- }
342
+ async getNewChannel({ name = rand().toString(), onClose = null }: newChannelOpts = {}) {
343
+ return new Promise<ChannelWrapper>(async (resolve, reject) => {
344
+ const connection: AmqpConnectionManager = await this.getConnection();
345
+ const channel = connection.createChannel({
346
+ });
397
347
 
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);
348
+ let isResolved = false;
349
+ channel.on('error', (err) => {
350
+ logger.error(`rabbit: channel ${name} error`, { err });
351
+ if (!isResolved) {
352
+ isResolved = true;
353
+ reject(err);
403
354
  }
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);
355
+ });
356
+ channel.on('close', (...args) => {
357
+ logger.error(`rabbit: channel ${name} closed`, { args });
358
+ if (onClose) {
359
+ onClose(args);
414
360
  }
415
361
  });
416
- }
417
- return this.publishChannelSetupPromise;
362
+ channel.once('connect', () => {
363
+ debug(`rabbit: channel ${name} CONNECTED`);
364
+ isResolved = true;
365
+ resolve(channel);
366
+ });
367
+ });
368
+ }
369
+
370
+ async assertChannel({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
371
+ return new Promise<ChannelWrapper>(async (resolve, reject) => {
372
+ if (this.channel && !force) {
373
+ return resolve(this.channel);
374
+ }
375
+
376
+ try {
377
+ const channel = await this.getNewChannel({
378
+ });
379
+ channel.on('error', (err) => {
380
+ logger.error('rabbit: channel error', { err });
381
+ });
382
+ this.channel = channel;
383
+ resolve(channel);
384
+ } catch (e) {
385
+ reject(e);
386
+ }
387
+ });
418
388
  }
419
389
 
420
390
  async assertExchange(exchangeName: string, options?: any) {
421
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: options.connectionPurpose });
391
+ const channel: ChannelWrapper = await this.assertChannel();
422
392
  if (this.exchanges[exchangeName]) {
423
393
  return this.exchanges[exchangeName];
424
394
  }
@@ -427,36 +397,36 @@ class RabbitMq implements IAfRabbitMq {
427
397
  return exchange;
428
398
  }
429
399
 
430
- async getQueueLength(queue: string, connectionPurpose: ConnectionPurpose = ConnectionPurpose.Consume): Promise<Replies.AssertQueue> {
400
+ async getQueueLength(queue: string) {
431
401
  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);
402
+ const channel: ChannelWrapper = await this.assertChannel();
403
+ debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
404
+ return channel.checkQueue(queue);
439
405
  }
440
406
 
441
- private async deleteQueue(queue: string, connectionPurpose: ConnectionPurpose) {
407
+ private async deleteQueue(queue: string) {
442
408
  RabbitMq.validateName('queue', queue);
443
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
409
+ const channel: ChannelWrapper = await this.assertChannel();
444
410
  logger.info('rabbit: deleting queue', { queue });
445
411
  const deleteQueueRes = await channel.deleteQueue(queue);
446
412
  debug('queue deleted', deleteQueueRes);
447
413
  return deleteQueueRes;
448
414
  }
449
415
 
450
- async bindQueue(queue: string, exchange: string, connectionPurpose: ConnectionPurpose) {
451
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
416
+ async bindQueue(queue: string, exchange: string) {
417
+ const channel: ChannelWrapper = await this.assertChannel();
452
418
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
453
419
  return channel.bindQueue(queue, exchange, '');
454
420
  }
455
421
 
456
- async setupQueue(queueName: string, connectionPurpose: ConnectionPurpose, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
457
- let queue: Replies.AssertQueue;
422
+ async assertQueue(queueName: string, options?: Options.AssertQueue) {
423
+ let queue: Replies.AssertQueue | null = null;
424
+ RabbitMq.validateName('queue', queueName);
425
+ if (this.queues[queueName]) {
426
+ return this.queues[queueName];
427
+ }
458
428
  try {
459
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
429
+ const channel: ChannelWrapper = await this.assertChannel();
460
430
  debug('assertQueue->channel.addSetup', { queueName });
461
431
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
462
432
  debug('assertQueue->channel.assertQueue', { queueName });
@@ -465,12 +435,12 @@ class RabbitMq implements IAfRabbitMq {
465
435
  logger.error('rabbit: assertQueue error', { queueName, options, error: e });
466
436
  if (!this.options?.dontRetryAssert) {
467
437
  debug('retrying assertQueue', { queueName });
468
- const channel = await this.assertChannel({ force: true, connectionPurpose });
469
- await this.deleteQueue(queueName, connectionPurpose);
438
+ const channel = await this.assertChannel({ force: true });
439
+ await this.deleteQueue(queueName);
470
440
 
471
- debug('retrying assertQueue->channel.addSetup', { queueName });
441
+ debug('1assertQueue->channel.addSetup', { queueName });
472
442
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
473
- debug('retrying assertQueue->channel.assertQueue', { queueName });
443
+ debug('1assertQueue->channel.assertQueue', { queueName });
474
444
  queue = await channel.assertQueue(queueName, options);
475
445
  } else {
476
446
  throw e;
@@ -481,35 +451,29 @@ class RabbitMq implements IAfRabbitMq {
481
451
  return queue;
482
452
  }
483
453
 
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];
454
+ private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
455
+ this.consumers.push({
456
+ queue,
457
+ callback,
458
+ options,
459
+ });
497
460
  }
498
461
 
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
- });
462
+ private async loadConsumers() {
463
+ debug('rabbit: loading consumers', { consumers: this.consumers.length });
464
+ if (this.consumers.length > 0) {
465
+ await Promise.all(
466
+ this.consumers.map((consumer) => this
467
+ .consumeFromRabbit(consumer.queue, consumer.callback, consumer.options)),
468
+ );
508
469
  }
509
470
  }
510
471
 
511
472
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
512
- await this.consumeFromRabbit(queue, callback, options);
473
+ if (this.connection && !this.creatingConnection) {
474
+ this.consumeFromRabbit(queue, callback, options);
475
+ }
476
+ return this.saveConsumer(queue, callback, options);
513
477
  }
514
478
 
515
479
  private async lockRedisIfNeeded(msg: any, options: any) {
@@ -535,8 +499,6 @@ class RabbitMq implements IAfRabbitMq {
535
499
  private async consumeFromRabbit(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
536
500
  const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
537
501
  RabbitMq.validateName('queue', queue);
538
- this.saveConsumer(queue, callback, options);
539
- const uniqueId = randomUUID();
540
502
  const {
541
503
  limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace,
542
504
  } = optionsWithDefaults;
@@ -546,11 +508,11 @@ class RabbitMq implements IAfRabbitMq {
546
508
  }
547
509
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
548
510
  }
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(
511
+ const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-queue-${queue}` });
512
+ return channel.addSetup(async (c: ConfirmChannel) => {
513
+ await c.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
514
+ await c.prefetch(limit, true);
515
+ const { consumerTag } = await c.consume(
554
516
  queue,
555
517
  async (msg: ConsumeMessageOrNull) => {
556
518
  if (!msg) {
@@ -574,7 +536,7 @@ class RabbitMq implements IAfRabbitMq {
574
536
  ]);
575
537
  } catch (e) {
576
538
  logger.error('rabbit: failed to setRabbitTrace', { userId, e });
577
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
539
+ await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
578
540
  }
579
541
  }
580
542
 
@@ -589,37 +551,16 @@ class RabbitMq implements IAfRabbitMq {
589
551
  const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
590
552
  if (!shouldConsume) {
591
553
  await this.unlockRedisIfNeeded(releaseLock);
592
- return this.ack(confirmChannel, msg)(msg);
554
+ return this.ack(channel, msg)(msg);
593
555
  }
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
556
  try {
616
557
  await callback(
617
558
  parsedMessage,
618
- localAck,
619
- localNack,
559
+ this.ack(channel, msg, true, releaseLock),
560
+ this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock),
620
561
  );
621
562
  } catch (e) {
622
- await localNack(msg);
563
+ await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
623
564
  }
624
565
  }, CONSUMER_DEFAULT_OPTIONS,
625
566
  );
@@ -627,18 +568,17 @@ class RabbitMq implements IAfRabbitMq {
627
568
  logger.error(`rabbit: failed to consume from queue ${queue}`);
628
569
  } else {
629
570
  logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
630
- this.consumersTags.push([confirmChannel, consumerTag]);
571
+ this.consumersTags.push([c, consumerTag]);
631
572
  }
632
573
  });
633
574
  }
634
575
 
635
- async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
576
+ async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
636
577
  const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
637
578
  RabbitMq.validateName('exchange', exchange);
638
579
  RabbitMq.validateName('queue', queue);
639
580
  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 });
581
+ const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
642
582
 
643
583
  return channel.addSetup(async (c: ConfirmChannel) => {
644
584
  const assertExchange = await assertExchangeFanout(c, exchange);
@@ -656,11 +596,11 @@ class RabbitMq implements IAfRabbitMq {
656
596
  });
657
597
  }
658
598
 
659
- async publish(exchange: string, content: any, customHeaders?: any): Promise<boolean> {
599
+ async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
660
600
  return wrapSetImmediate(async () => {
661
601
  RabbitMq.validateName('exchange', exchange);
662
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
663
- await this.assertExchange(exchange, { connectionPurpose: ConnectionPurpose.Publish });
602
+ const channel: ChannelWrapper = await this.assertChannel();
603
+ await this.assertExchange(exchange);
664
604
  await channel.publish(exchange, '',
665
605
  Buffer.from(JSON.stringify(content)),
666
606
  RabbitMq.getPublishOptions(customHeaders));
@@ -672,61 +612,35 @@ class RabbitMq implements IAfRabbitMq {
672
612
  content: any,
673
613
  options?: any,
674
614
  customHeaders?: any,
615
+ isBlocking?: boolean,
675
616
  ): 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;
617
+ const callback = async (): Promise<boolean | undefined> => {
618
+ try {
619
+ RabbitMq.validateName('queue', queue);
620
+ await this.assertChannel();
621
+ await this.assertQueue(queue, options);
622
+ const res = await this.channel?.sendToQueue(queue,
623
+ Buffer.from(JSON.stringify(content)),
624
+ RabbitMq.getPublishOptions(customHeaders));
625
+ debug(`rabbit: sending to queue ${queue}`, { res });
626
+ return res;
627
+ } catch (e) {
628
+ logger.error(`rabbit: failed to send to queue ${queue}`, { e });
629
+ throw e;
630
+ }
631
+ };
632
+ if (isBlocking) {
633
+ return callback();
701
634
  }
635
+ return wrapSetImmediate(callback);
702
636
  }
703
637
 
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;
638
+ async isConnected() : Promise<boolean> {
639
+ const connection = await this.getConnection();
640
+ return connection.isConnected();
727
641
  }
728
642
 
729
- async gracefulShutdown(signal: string): Promise<void> {
643
+ async gracefulShutdown(signal: string) : Promise<void> {
730
644
  const tagsNumber = this.consumersTags.length;
731
645
  logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
732
646
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));