@autofleet/rabbit 3.3.0-beta.11 → 3.3.0-beta.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
@@ -20,8 +20,7 @@ import getRedisInstance, { RedisConfig } from './lib/redis';
20
20
  import { assertExchangeFanout, rand, wrapSetImmediate } from './lib/utils';
21
21
  import {
22
22
  AUTOMATION_ID_HEADER,
23
- CONNECTION_CREATED_CONST,
24
- CONNECTION_FAILED_CONST,
23
+ ConnectionPurpose,
25
24
  DEFAULT_LOCK_TIMEOUT,
26
25
  DEFAULT_OPTIONS,
27
26
  RETRY_HEADER,
@@ -40,13 +39,13 @@ import {
40
39
  CONSUMER_DEFAULT_OPTIONS,
41
40
  QueueSetupPromisesDictionary,
42
41
  AssertExchangePromisesDictionary,
42
+ ConnectionData,
43
43
  } from './lib/types';
44
44
 
45
45
  // const debug = nodeDebug('af-rabbitmq')
46
46
  const debug = logger.debug.bind(logger);
47
47
 
48
48
  const PUBLISH_TIMEOUT = 1000 * 10;
49
-
50
49
  export interface IAfRabbitMq {
51
50
  ack: any;
52
51
  nack: any;
@@ -86,11 +85,13 @@ type newChannelOpts = {
86
85
  name?: string;
87
86
  onClose?: null | ((args: any | null) => void);
88
87
  options?: CreateChannelOpts | undefined;
88
+ connectionPurpose?: ConnectionPurpose,
89
89
  };
90
90
 
91
91
  type assertChannelOpts = {
92
92
  channelName?: string;
93
93
  force?: boolean;
94
+ connectionPurpose?: ConnectionPurpose;
94
95
  }
95
96
 
96
97
  type AfConsumer = {
@@ -102,7 +103,7 @@ type AfConsumer = {
102
103
  const HEARTBEAT = '60';
103
104
 
104
105
  class RabbitMq implements IAfRabbitMq {
105
- static parseMsg(msg: any) : any {
106
+ static parseMsg(msg: any): any {
106
107
  let { content } = msg;
107
108
  content = content.toString();
108
109
 
@@ -143,18 +144,17 @@ class RabbitMq implements IAfRabbitMq {
143
144
 
144
145
  RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
145
146
 
146
- channel: ChannelWrapper | null;
147
+ publishChannel: ChannelWrapper | null;
147
148
 
148
149
  publishChannelSetupPromise: Promise<ChannelWrapper> | null;
149
150
 
150
- blockReconnect: boolean | null | undefined
151
-
152
- connection: AmqpConnectionManager | null | undefined
151
+ connectionsMap: {
152
+ [ConnectionPurpose.Consume]: ConnectionData;
153
+ [ConnectionPurpose.Publish]: ConnectionData;
154
+ };
153
155
 
154
156
  em: EventEmitter;
155
157
 
156
- creatingConnection: boolean;
157
-
158
158
  exchanges: ExchangesCache;
159
159
 
160
160
  queues: QueuesCache;
@@ -174,48 +174,32 @@ class RabbitMq implements IAfRabbitMq {
174
174
 
175
175
  private consumers: Array<AfConsumer> = [];
176
176
 
177
- private doesVHostExist = false;
178
-
179
- private vhost = 'quorum-vhost';
180
-
181
- // TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
182
- oldChannel: ChannelWrapper | null;
183
-
184
- oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null;
185
-
186
- oldBlockReconnect: boolean | null | undefined
187
-
188
- oldConnection: AmqpConnectionManager | null | undefined
189
-
190
- oldEm: EventEmitter;
191
-
192
- oldCreatingConnection: boolean;
193
-
194
- oldExchanges: ExchangesCache;
195
-
196
- oldQueues: QueuesCache;
197
-
198
- oldQueueSetupPromises: QueueSetupPromisesDictionary;
199
-
200
- oldAssertExchangePromises: AssertExchangePromisesDictionary;
201
-
202
- oldConsumersTags: Array<[ConfirmChannel, string]>;
203
-
204
- private oldConsumers: Array<AfConsumer> = [];
205
-
206
- constructor(options: AfRabbitOptions = {}, redisConfig?: RedisConfig) {
177
+ constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig) {
207
178
  this.em = new EventEmitter();
208
- this.channel = null;
179
+ this.publishChannel = null;
209
180
  this.publishChannelSetupPromise = null;
210
- this.connection = null;
211
- this.creatingConnection = false;
181
+ this.connectionsMap = {
182
+ [ConnectionPurpose.Consume]: {
183
+ connection: null,
184
+ creatingConnection: false,
185
+ connectionCreatedEventName: 'consumeConnectionCreated',
186
+ connectionFailedEventName: 'consumeConnectionFailed',
187
+ blockReconnect: false,
188
+ },
189
+ [ConnectionPurpose.Publish]: {
190
+ connection: null,
191
+ creatingConnection: false,
192
+ connectionCreatedEventName: 'publishConnectionCreated',
193
+ connectionFailedEventName: 'publishConnectionFailed',
194
+ blockReconnect: false,
195
+ },
196
+ };
212
197
  this.exchanges = {};
213
198
  this.queues = {};
214
199
  this.queueSetupPromises = {};
215
200
  this.assertExchangePromises = {};
216
201
  this.consumers = [];
217
202
  this.options = options;
218
-
219
203
  this.redisClient = redisConfig && getRedisInstance(redisConfig);
220
204
  if (this.redisClient) {
221
205
  this.redisLock = promisify(RedisLock(this.redisClient)) as RedisLockType;
@@ -230,74 +214,8 @@ class RabbitMq implements IAfRabbitMq {
230
214
  await this.gracefulShutdown('SIGINT');
231
215
  });
232
216
  }
233
-
234
- // TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
235
- this.oldEm = new EventEmitter();
236
- this.oldChannel = null;
237
- this.oldPublishChannelSetupPromise = null;
238
- this.oldConnection = null;
239
- this.oldCreatingConnection = false;
240
- this.oldExchanges = {};
241
- this.oldQueues = {};
242
- this.oldQueueSetupPromises = {};
243
- this.oldAssertExchangePromises = {};
244
- this.oldConsumers = [];
245
- this.oldConsumersTags = [];
246
217
  }
247
218
 
248
- private assertVHost = async () => {
249
- if (this.doesVHostExist) {
250
- return;
251
- }
252
-
253
- const username = process.env.RABBITMQ_USERNAME || 'guest';
254
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
255
- const credentials = Buffer.from(`${username}:${password}`).toString('base64');
256
- const headers = {
257
- Authorization: `Basic ${credentials}`,
258
- 'Content-Type': 'application/json',
259
- };
260
-
261
- const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
262
-
263
- const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
264
-
265
- try {
266
- const response = await fetch(url, {
267
- method: 'GET',
268
- headers,
269
- });
270
-
271
- if (response.status === 200) {
272
- this.doesVHostExist = true;
273
- logger.info('Vhost exists', { vhost: this.vhost });
274
- return;
275
- }
276
-
277
- if (response.status !== 404) {
278
- logger.error('Failed to check vhost', { response });
279
- throw new RabbitError('Failed to check vhost');
280
- }
281
-
282
- const createResponse = await fetch(url, {
283
- method: 'PUT',
284
- headers,
285
- body: JSON.stringify({ default_queue_type: 'quorum' }),
286
- });
287
-
288
- if (!createResponse.ok) {
289
- logger.error('Failed to create vhost', { response: createResponse });
290
- throw new RabbitError('Failed to create vhost');
291
- }
292
-
293
- this.doesVHostExist = true;
294
- logger.info('Vhost created', { vhost: this.vhost });
295
- } catch (error) {
296
- logger.error('Failed to check or create vhost', { error });
297
- throw error;
298
- }
299
- };
300
-
301
219
  private shouldConsumeMessageByTimestamp = async (msg: ConsumeMessageOrNull) => {
302
220
  if (msg) {
303
221
  const { properties: { headers } } = msg;
@@ -312,7 +230,7 @@ class RabbitMq implements IAfRabbitMq {
312
230
  return false;
313
231
  }
314
232
 
315
- public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
233
+ public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage): Promise<any> => {
316
234
  if (msg) {
317
235
  debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
318
236
  await channel.ack(msg);
@@ -338,8 +256,8 @@ class RabbitMq implements IAfRabbitMq {
338
256
  userMsg: ConsumeMessageOrNull,
339
257
  {
340
258
  skipRetry = false,
341
- }: NackOptions = { },
342
- ) : Promise<any> => {
259
+ }: NackOptions = {},
260
+ ): Promise<any> => {
343
261
  await this.unlockRedisIfNeeded(releaseLock);
344
262
  if (channel && msg) {
345
263
  if (
@@ -373,30 +291,38 @@ class RabbitMq implements IAfRabbitMq {
373
291
  }
374
292
  }
375
293
 
376
- async getConnection() {
377
- return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
378
- if (this.blockReconnect) {
294
+ async getConnection(connectionPurpose: ConnectionPurpose) {
295
+ return new Promise<AmqpConnectionManager | undefined | null>(async (resolve, reject) => {
296
+ const {
297
+ connection,
298
+ creatingConnection,
299
+ connectionCreatedEventName,
300
+ connectionFailedEventName,
301
+ blockReconnect,
302
+ } = this.connectionsMap[connectionPurpose];
303
+
304
+ if (blockReconnect) {
379
305
  debug('rabbit: block reconnect');
380
306
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
381
307
  // @ts-ignore
382
308
  return resolve();
383
309
  }
384
- if (this.connection !== null) {
385
- if (this.options?.disableReconnect || this.connection?.isConnected()) {
310
+ if (connection !== null) {
311
+ if (this.options?.disableReconnect || connection?.isConnected()) {
386
312
  debug('rabbit: connection - is connected');
387
313
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
388
314
  // @ts-ignore
389
- return resolve(this.connection);
315
+ return resolve(connection);
390
316
  }
391
317
  debug('rabbit: connection - reconnecting');
392
318
  }
393
- if (this.creatingConnection) {
319
+ if (creatingConnection) {
394
320
  debug('rabbit: creating connection emi');
395
- this.em.once(CONNECTION_CREATED_CONST, resolve);
396
- this.em.once(CONNECTION_FAILED_CONST, reject);
321
+ this.em.once(connectionCreatedEventName, resolve);
322
+ this.em.once(connectionFailedEventName, reject);
397
323
  return;
398
324
  }
399
- this.creatingConnection = true;
325
+ this.connectionsMap[connectionPurpose].creatingConnection = true;
400
326
  let isResolved = false;
401
327
 
402
328
  // It is import to use it as a function and not as a variable
@@ -408,64 +334,69 @@ class RabbitMq implements IAfRabbitMq {
408
334
  const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
409
335
 
410
336
  debug('rabbit: creating connection', { host, userName, HEARTBEAT });
411
- return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
337
+
338
+ return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
412
339
  };
413
340
 
414
341
  const defaultUrls = findServers();
415
- const connection: AmqpConnectionManager = await connect(defaultUrls, {
342
+ const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
416
343
  findServers,
417
344
  });
418
345
 
419
- this.connection = connection;
420
- this.connection.on('error', (err) => {
346
+ this.connectionsMap[connectionPurpose].connection = newConnection;
347
+ logger.info(`rabbit: created new connection ${connectionPurpose}`);
348
+
349
+ newConnection.on('error', (err) => {
421
350
  logger.error('rabbit: connection error', { err });
422
351
  if (!isResolved) {
423
352
  isResolved = true;
424
353
  reject(err);
425
- this.em.emit(CONNECTION_FAILED_CONST, err);
354
+ this.em.emit(connectionFailedEventName, err);
426
355
  }
427
356
  });
428
357
 
429
- this.connection.on('connectFailed', (err) => {
358
+ newConnection.on('connectFailed', (err) => {
430
359
  this.consumersTags = [];
431
- logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
360
+ logger.error('rabbit: connection connectFailed', { err });
432
361
  if (!isResolved) {
433
362
  isResolved = true;
434
363
  reject(err);
435
- this.em.emit(CONNECTION_FAILED_CONST, err);
364
+ this.em.emit(connectionFailedEventName, err);
436
365
  }
437
366
  });
438
367
 
439
- this.connection.on('disconnect', ({ err }) => {
440
- // this.channel = null;
368
+ newConnection.on('disconnect', ({ err }) => {
441
369
  this.consumersTags = [];
442
370
  debug('rabbit: connection closed');
443
371
  if (this.options?.disableReconnect) {
444
372
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
445
- this.blockReconnect = true;
373
+ this.connectionsMap[connectionPurpose].blockReconnect = true;
446
374
  } else {
447
375
  logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
448
376
  }
449
377
  });
450
-
451
- this.connection.once('connect', async () => {
452
- debug('rabbit: connection established');
453
- this.creatingConnection = false;
454
- this.em.emit(CONNECTION_CREATED_CONST, connection);
378
+ newConnection.once('connect', async () => {
379
+ this.connectionsMap[connectionPurpose].creatingConnection = false;
380
+ this.em.emit(connectionCreatedEventName, newConnection);
455
381
  isResolved = true;
456
- resolve(connection);
382
+ resolve(newConnection);
457
383
  });
458
384
  });
459
385
  }
460
386
 
461
- async getNewChannel({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
462
- let connection!: AmqpConnectionManager;
387
+ async getNewChannel({
388
+ name = rand().toString(), onClose = null, options = {}, connectionPurpose = ConnectionPurpose.Consume,
389
+ }: newChannelOpts): Promise<ChannelWrapper> {
390
+ let connection!: AmqpConnectionManager | undefined | null;
463
391
  try {
464
- connection = await this.getConnection();
392
+ connection = await this.getConnection(connectionPurpose);
465
393
  } catch (e) {
466
394
  logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
467
395
  throw e;
468
396
  }
397
+ if (!connection) {
398
+ throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
399
+ }
469
400
  const channel = connection.createChannel({ ...options });
470
401
  once(channel, 'close').then((args) => {
471
402
  logger.error(`rabbit: channel ${name} closed`);
@@ -481,19 +412,23 @@ class RabbitMq implements IAfRabbitMq {
481
412
  }
482
413
  }
483
414
 
484
- async assertChannel({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
415
+ async assertChannel({ force = false, connectionPurpose = ConnectionPurpose.Consume }: assertChannelOpts): Promise<ChannelWrapper> {
416
+ debug('rabbit: start assert channel', { connectionPurpose, publishPromise: this.publishChannelSetupPromise, channel: this.publishChannel });
485
417
  if (!this.publishChannelSetupPromise) {
486
418
  this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
487
- if (this.channel && !force) {
488
- return resolve(this.channel);
419
+ if (this.publishChannel && !force) {
420
+ return resolve(this.publishChannel);
489
421
  }
490
422
 
491
423
  try {
492
- const channel = await this.getNewChannel({});
424
+ const channel = await this.getNewChannel({ connectionPurpose });
425
+ debug('rabbit: new channel got', { connectionPurpose, channel: this.publishChannel });
493
426
  channel.on('error', (err) => {
494
427
  logger.error('rabbit: channel error', { err });
495
428
  });
496
- this.channel = channel;
429
+ if (connectionPurpose === ConnectionPurpose.Publish) {
430
+ this.publishChannel = channel;
431
+ }
497
432
  resolve(channel);
498
433
  } catch (e) {
499
434
  reject(e);
@@ -503,9 +438,8 @@ class RabbitMq implements IAfRabbitMq {
503
438
  return this.publishChannelSetupPromise;
504
439
  }
505
440
 
506
- async assertExchange(exchangeName: string, options?: any) {
507
- const channel: ChannelWrapper = await this.assertChannel();
508
-
441
+ async assertExchange(exchangeName: string, options: any = { connectionPurpose: ConnectionPurpose.Consume }) {
442
+ const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: options.connectionPurpose });
509
443
  if (this.exchanges[exchangeName]) {
510
444
  delete this.assertExchangePromises[exchangeName];
511
445
  return this.exchanges[exchangeName];
@@ -520,58 +454,57 @@ class RabbitMq implements IAfRabbitMq {
520
454
  return this.exchanges[exchangeName];
521
455
  }
522
456
 
523
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
524
- async getQueueLength(queue: string) {
457
+ async getQueueLength(queue: string, connectionPurpose: ConnectionPurpose = ConnectionPurpose.Consume): Promise<Replies.AssertQueue> {
525
458
  RabbitMq.validateName('queue', queue);
526
- const { oldChannel: channel } = this;
527
- if (!channel) {
528
- throw new RabbitError('channel is not defined');
459
+ const { connection } = this.connectionsMap[connectionPurpose];
460
+ const { publishChannel } = this;
461
+ if (!publishChannel) {
462
+ throw new Error('channel is not defined');
529
463
  }
530
- debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
531
- return channel?.checkQueue(queue);
464
+ debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
465
+ return publishChannel?.checkQueue(queue);
532
466
  }
533
467
 
534
- private async deleteQueue(queue: string) {
468
+ private async deleteQueue(queue: string, connectionPurpose: ConnectionPurpose) {
535
469
  RabbitMq.validateName('queue', queue);
536
- const channel: ChannelWrapper = await this.assertChannel();
470
+ const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
537
471
  logger.info('rabbit: deleting queue', { queue });
538
472
  const deleteQueueRes = await channel.deleteQueue(queue);
539
473
  debug('queue deleted', deleteQueueRes);
540
474
  return deleteQueueRes;
541
475
  }
542
476
 
543
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
544
477
  async bindQueue(queue: string, exchange: string) {
545
- const channel: ChannelWrapper = await this.assertChannelOld();
478
+ const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
546
479
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
547
480
  return channel.bindQueue(queue, exchange, '');
548
481
  }
549
482
 
550
483
  async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
551
484
  let queue: Replies.AssertQueue;
485
+ const connectionPurpose = ConnectionPurpose.Publish;
486
+ const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
552
487
  const localeOptions = {
553
488
  ...options,
554
489
  durable: true,
555
490
  arguments: {
556
491
  ...options?.arguments,
557
492
  'x-consumer-timeout': 1000 * 60 * 60 * 24,
558
- 'x-queue-type': 'quorum',
493
+ 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
559
494
  },
560
495
  };
561
496
  try {
562
- const channel: ChannelWrapper = await this.assertChannel();
497
+ const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
563
498
  debug('assertQueue->channel.addSetup', { queueName });
564
- await channel.addSetup(async (setupChannel: ConfirmChannel) => {
565
- await setupChannel.assertQueue(queueName, localeOptions);
566
- });
499
+ await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
567
500
  debug('assertQueue->channel.assertQueue', { queueName });
568
501
  queue = await channel.assertQueue(queueName, localeOptions);
569
502
  } catch (e) {
570
503
  logger.error('rabbit: assertQueue error', { queueName, options, error: e });
571
504
  if (!this.options?.dontRetryAssert) {
572
505
  debug('retrying assertQueue', { queueName });
573
- const channel = await this.assertChannel({ force: true });
574
- await this.deleteQueue(queueName);
506
+ const channel = await this.assertChannel({ force: true, connectionPurpose });
507
+ await this.deleteQueue(queueName, connectionPurpose);
575
508
 
576
509
  debug('retrying assertQueue->channel.addSetup', { queueName });
577
510
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
@@ -586,7 +519,6 @@ class RabbitMq implements IAfRabbitMq {
586
519
  return queue;
587
520
  }
588
521
 
589
- // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
590
522
  static shouldUseQuorum(queueName: string): boolean {
591
523
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
592
524
 
@@ -602,7 +534,8 @@ class RabbitMq implements IAfRabbitMq {
602
534
  return false;
603
535
  }
604
536
 
605
- async assertQueue(queueName: string, options?: Options.AssertQueue): Promise<any> {
537
+ async assertQueue(queueName: string, options?: Options.AssertQueue) {
538
+ debug('rabbit: start assert queue', { queueName });
606
539
  RabbitMq.validateName('queue', queueName);
607
540
  if (this.queues[queueName]) {
608
541
  delete this.queueSetupPromises[queueName];
@@ -614,11 +547,12 @@ class RabbitMq implements IAfRabbitMq {
614
547
  }
615
548
 
616
549
  this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
550
+ debug('rabbit: done assert queue', { queueName });
617
551
  return this.queueSetupPromises[queueName];
618
552
  }
619
553
 
620
554
  private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
621
- const isConsumerExist :boolean = this.consumers.some((consumer) => consumer.queue === queue);
555
+ const isConsumerExist: boolean = this.consumers.some((consumer) => consumer.queue === queue);
622
556
  if (!isConsumerExist) {
623
557
  logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
624
558
  this.consumers.push({
@@ -629,27 +563,10 @@ class RabbitMq implements IAfRabbitMq {
629
563
  }
630
564
  }
631
565
 
632
- // Used by the microservices to consume messages from the queue
633
566
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
634
- // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
635
- if (options?.isQuorumQueue !== false) {
636
- await this.assertVHost();
637
- await this.consumeNew(queue, callback, options);
638
- }
639
-
640
- await this.consumeOld(queue, callback, options);
641
- }
642
-
643
- // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
644
- async consumeNew(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
645
567
  await this.consumeFromRabbit(queue, callback, options);
646
568
  }
647
569
 
648
- // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
649
- async consumeOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
650
- await this.consumeFromRabbitOld(queue, callback, options);
651
- }
652
-
653
570
  private async lockRedisIfNeeded(msg: any, options: any) {
654
571
  const { properties: { headers } } = msg;
655
572
  const timestamp = headers?.creationTimestamp;
@@ -680,13 +597,12 @@ class RabbitMq implements IAfRabbitMq {
680
597
  } = optionsWithDefaults;
681
598
  if (useConsumeWithLock) {
682
599
  if (!this.redisLock) {
683
- throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
600
+ throw new Error('Usage of consumeWithLock requires RedisInstance');
684
601
  }
685
602
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
686
603
  }
687
- const channel = await this.getNewChannel({});
604
+ const channel = await this.getNewChannel({ connectionPurpose: ConnectionPurpose.Consume });
688
605
  return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
689
- throw new Error('Dummy assertQueue error');
690
606
  const q = await this.assertQueue(queue, optionsWithDefaults);
691
607
  await confirmChannel.prefetch(limit, false);
692
608
  const { consumerTag } = await confirmChannel.consume(
@@ -775,45 +691,22 @@ class RabbitMq implements IAfRabbitMq {
775
691
  });
776
692
  }
777
693
 
778
- // Used by the microservices to consume messages from the exchange
779
- async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
694
+ async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
780
695
  const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
781
696
  RabbitMq.validateName('exchange', exchange);
782
697
  RabbitMq.validateName('queue', queue);
783
698
  const { limit, deadMessageTtl } = optionsWithDefaults;
784
- // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
785
- if (options?.isQuorumQueue !== false) {
786
- await this.assertVHost();
787
- await this.saveConsumer(queue, callback, options);
788
- const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
789
-
790
- await channel.addSetup(async (c: ConfirmChannel) => {
791
- const assertExchange = await assertExchangeFanout(c, exchange);
792
- await c.assertQueue(queue);
793
- this.exchanges[exchange] = assertExchange;
794
- await c.prefetch(limit, false);
795
- return Promise.all([
796
- c.bindQueue(queue, exchange, ''),
797
- this.consumeNew(
798
- queue,
799
- callback,
800
- options,
801
- ),
802
- ]);
803
- });
804
- }
699
+ await this.saveConsumer(queue, callback, options);
700
+ const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
805
701
 
806
- // TODO: [QUORUM-PHASE-3] Delete the old implementation
807
- await this.saveConsumerOld(queue, callback, options);
808
- const channelOld: ChannelWrapper = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
809
- await channelOld.addSetup(async (c: ConfirmChannel) => {
702
+ return channel.addSetup(async (c: ConfirmChannel) => {
810
703
  const assertExchange = await assertExchangeFanout(c, exchange);
811
704
  await c.assertQueue(queue);
812
- this.oldExchanges[exchange] = assertExchange;
705
+ this.exchanges[exchange] = assertExchange;
813
706
  await c.prefetch(limit, false);
814
707
  return Promise.all([
815
708
  c.bindQueue(queue, exchange, ''),
816
- this.consumeOld(
709
+ this.consume(
817
710
  queue,
818
711
  callback,
819
712
  options,
@@ -822,21 +715,18 @@ class RabbitMq implements IAfRabbitMq {
822
715
  });
823
716
  }
824
717
 
825
- // Used by the microservices to publish messages to the exchange
826
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
827
- async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
718
+ async publish(exchange: string, content: any, customHeaders?: any): Promise<boolean> {
719
+ debug('rabbit: start publish msg');
828
720
  return wrapSetImmediate(async () => {
829
721
  RabbitMq.validateName('exchange', exchange);
830
- const channel: ChannelWrapper = await this.assertChannelOld();
831
- await this.assertExchangeOld(exchange);
722
+ const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
723
+ await this.assertExchange(exchange, { connectionPurpose: ConnectionPurpose.Publish });
832
724
  await channel.publish(exchange, '',
833
725
  Buffer.from(JSON.stringify(content)),
834
726
  RabbitMq.getPublishOptions(customHeaders));
835
727
  });
836
728
  }
837
729
 
838
- // Used by the microservices to send messages to the queue
839
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
840
730
  async sendToQueue(
841
731
  queue: string,
842
732
  content: any,
@@ -844,7 +734,7 @@ class RabbitMq implements IAfRabbitMq {
844
734
  customHeaders?: any,
845
735
  ): Promise<boolean | undefined> {
846
736
  try {
847
- await this.assertChannelOld();
737
+ await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
848
738
  } catch (e) {
849
739
  logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
850
740
  throw e;
@@ -852,57 +742,61 @@ class RabbitMq implements IAfRabbitMq {
852
742
 
853
743
  try {
854
744
  RabbitMq.validateName('queue', queue);
855
- await this.assertQueueOld(queue, options);
745
+ await this.assertQueue(queue, options);
856
746
  } catch (e) {
857
747
  logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
858
748
  throw e;
859
749
  }
860
750
 
861
751
  try {
862
- const res = await this.oldChannel?.sendToQueue(queue,
752
+ const res = await this.publishChannel?.sendToQueue(queue,
863
753
  Buffer.from(JSON.stringify(content)),
864
754
  RabbitMq.getPublishOptions(customHeaders));
865
755
  debug(`rabbit: sending to queue ${queue}`, { res });
866
756
  return res;
867
757
  } catch (e) {
868
- const isConnected = await this.isConnected();
869
- logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
758
+ logger.error(`rabbit sendToQueue: failed to send to queue ${queue}`, { e });
870
759
  throw e;
871
760
  }
872
761
  }
873
762
 
874
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
875
- async isConnected() : Promise<boolean> {
876
- const connection = await this.getConnectionOld();
877
- const isConnected = connection.isConnected();
878
- if (!isConnected) {
879
- logger.error('rabbit: isConnected - false');
880
- return false;
881
- }
882
- const channel: any = await this.assertChannelOld();
883
- try {
884
- await Promise.all([
885
- channel.waitForConnect(),
886
- ...this.oldConsumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
887
- ]);
888
- } catch (e) {
889
- logger.error('rabbit: isConnected - false');
890
- return false;
891
- }
892
- logger.info('rabbit: isConnected - true');
893
- return true;
763
+ async isConnected(): Promise<boolean> {
764
+ debug('rabbit: start is connected');
765
+ const isEachConnectionConnected = await Promise.all(
766
+ Object.keys(this.connectionsMap).map(async (connectionPurpose) => {
767
+ const connection = await this.getConnection(connectionPurpose as ConnectionPurpose);
768
+ const isConnected = connection?.isConnected();
769
+ if (!isConnected) {
770
+ logger.error('rabbit: isConnected - false', { connectionPurpose });
771
+ return false;
772
+ }
773
+
774
+ if (connectionPurpose === ConnectionPurpose.Publish) {
775
+ const channel: any = await this.assertChannel({ connectionPurpose: connectionPurpose as ConnectionPurpose });
776
+ try {
777
+ await Promise.all([
778
+ channel.waitForConnect(),
779
+ ...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
780
+ ]);
781
+ } catch (e) {
782
+ logger.error('rabbit: isConnected - false');
783
+ return false;
784
+ }
785
+ }
786
+ logger.info('rabbit: isConnected - true', { connectionPurpose });
787
+ return true;
788
+ }),
789
+ );
790
+ return isEachConnectionConnected.every((isConnected) => isConnected === true);
894
791
  }
895
792
 
896
- async gracefulShutdown(signal: string) : Promise<void> {
897
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
898
- const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
793
+ async gracefulShutdown(signal: string): Promise<void> {
794
+ const tagsNumber = this.consumersTags.length;
899
795
  logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
900
796
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
901
- const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
902
797
  // Clean the array to avoid race
903
798
  this.consumersTags = [];
904
- this.oldConsumersTags = [];
905
- const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
799
+ const results = await Promise.allSettled(cancelTagPromises);
906
800
  const rejected = results.filter((p) => p.status === 'rejected');
907
801
  if (rejected.length > 0) {
908
802
  logger.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
@@ -910,332 +804,6 @@ class RabbitMq implements IAfRabbitMq {
910
804
  logger.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
911
805
  }
912
806
  }
913
-
914
- private async consumeFromRabbitOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
915
- const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
916
- RabbitMq.validateName('queue', queue);
917
- this.saveConsumerOld(queue, callback, options);
918
- const uniqueId = randomUUID();
919
- const {
920
- limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace,
921
- } = optionsWithDefaults;
922
- if (useConsumeWithLock) {
923
- if (!this.redisLock) {
924
- throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
925
- }
926
- logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
927
- }
928
- const channel = await this.getNewChannelOld({});
929
- return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
930
- const q = await this.assertQueueOld(queue, optionsWithDefaults);
931
- await confirmChannel.prefetch(limit, false);
932
- const { consumerTag } = await confirmChannel.consume(
933
- queue,
934
- async (msg: ConsumeMessageOrNull) => {
935
- if (!msg) {
936
- return null;
937
- }
938
-
939
- const traceId = msg.properties.headers[TRACING_HEADER];
940
- const userId = msg.properties.headers[USER_TRACING_HEADER];
941
- const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
942
- const parsedMessage = RabbitMq.parseMsg(msg);
943
- const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
944
- const trace = newTrace(traceTypes.RABBIT);
945
- // setting also outbreak trace as part of legacy code
946
- const outbreakTrace = outbreak.newTrace(traceTypes.RABBIT);
947
- // enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
948
- // and we don't want to fail the flow because of it
949
- if (userId && enableRabbitTrace) {
950
- try {
951
- await Promise.all([
952
- createOrSetRabbitTrace(trace, userId),
953
- createOrSetRabbitTrace(outbreakTrace, userId),
954
- ]);
955
- } catch (e) {
956
- logger.error('rabbit: failed to setRabbitTrace', { userId, e });
957
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
958
- }
959
- }
960
-
961
- if (traceId) {
962
- (trace as any)?.context?.set(TRACING_HEADER, traceId);
963
- (outbreakTrace as any)?.context.set(TRACING_HEADER, traceId);
964
- }
965
-
966
- if (auditContext) {
967
- await auditContext(queue, {
968
- userId,
969
- automationId,
970
- });
971
- }
972
- const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
973
- if (!shouldConsume) {
974
- await this.unlockRedisIfNeeded(releaseLock);
975
- return this.ack(confirmChannel, msg)(msg);
976
- }
977
-
978
- let messageAcked = false;
979
- // setting the localAck function to be used in the callback
980
-
981
- const localAck = async () => {
982
- if (messageAcked) {
983
- return;
984
- }
985
- messageAcked = true;
986
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
987
- };
988
-
989
- const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
990
- if (messageAcked) {
991
- return;
992
- }
993
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
994
- messageAcked = true;
995
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
996
- };
997
-
998
- try {
999
- await callback(
1000
- parsedMessage,
1001
- localAck,
1002
- localNack,
1003
- );
1004
- } catch (e) {
1005
- await localNack(msg);
1006
- }
1007
- }, CONSUMER_DEFAULT_OPTIONS,
1008
- );
1009
- if (!consumerTag) {
1010
- logger.error(`rabbit: failed to consume from queue ${queue}`);
1011
- } else {
1012
- logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
1013
- this.oldConsumersTags.push([confirmChannel, consumerTag]);
1014
- }
1015
- });
1016
- }
1017
-
1018
- // TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
1019
- async getNewChannelOld({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
1020
- let connection!: AmqpConnectionManager;
1021
- try {
1022
- connection = await this.getConnectionOld();
1023
- } catch (e) {
1024
- logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
1025
- throw e;
1026
- }
1027
- const channel = connection.createChannel({ ...options });
1028
- once(channel, 'close').then((args) => {
1029
- logger.error(`rabbit: channel ${name} closed`);
1030
- onClose?.(args);
1031
- });
1032
- try {
1033
- await once(channel, 'connect');
1034
- debug(`rabbit: channel ${name} CONNECTED`);
1035
- return channel;
1036
- } catch (err) {
1037
- logger.error(`rabbit: channel error ${name} error`, { err });
1038
- throw err;
1039
- }
1040
- }
1041
-
1042
- async getConnectionOld() {
1043
- return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
1044
- if (this.oldBlockReconnect) {
1045
- debug('rabbit: block reconnect');
1046
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1047
- // @ts-ignore
1048
- return resolve();
1049
- }
1050
- if (this.oldConnection !== null) {
1051
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
1052
- debug('rabbit: connection - is connected');
1053
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1054
- // @ts-ignore
1055
- return resolve(this.oldConnection);
1056
- }
1057
- debug('rabbit: connection - reconnecting');
1058
- }
1059
- if (this.oldCreatingConnection) {
1060
- debug('rabbit: creating connection emi');
1061
- this.oldEm.once(CONNECTION_CREATED_CONST, resolve);
1062
- this.oldEm.once(CONNECTION_FAILED_CONST, reject);
1063
- return;
1064
- }
1065
- this.oldCreatingConnection = true;
1066
- let isResolved = false;
1067
-
1068
- // It is import to use it as a function and not as a variable
1069
- // because of k8s changes the env variables
1070
- // and we want to use the new values
1071
- const findServers = () => {
1072
- const userName = process.env.RABBITMQ_USERNAME || 'guest';
1073
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
1074
- const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
1075
-
1076
- debug('rabbit: creating connection', { host, userName, HEARTBEAT });
1077
-
1078
- return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
1079
- };
1080
-
1081
- const defaultUrls = findServers();
1082
- const connection: AmqpConnectionManager = await connect(defaultUrls, {
1083
- findServers,
1084
- });
1085
-
1086
- this.oldConnection = connection;
1087
- this.oldConnection.on('error', (err) => {
1088
- logger.error('rabbit: connection error', { err });
1089
- if (!isResolved) {
1090
- isResolved = true;
1091
- reject(err);
1092
- this.oldEm.emit(CONNECTION_FAILED_CONST, err);
1093
- }
1094
- });
1095
-
1096
- this.oldConnection.on('connectFailed', (err) => {
1097
- this.oldConsumersTags = [];
1098
- logger.error('rabbit: connection connectFailed', { err });
1099
- if (!isResolved) {
1100
- isResolved = true;
1101
- reject(err);
1102
- this.oldEm.emit(CONNECTION_FAILED_CONST, err);
1103
- }
1104
- });
1105
-
1106
- this.oldConnection.on('disconnect', ({ err }) => {
1107
- this.oldConsumersTags = [];
1108
- debug('rabbit: connection closed');
1109
- if (this.options?.disableReconnect) {
1110
- logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
1111
- this.oldBlockReconnect = true;
1112
- } else {
1113
- logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
1114
- }
1115
- });
1116
-
1117
- this.oldConnection.once('connect', async () => {
1118
- debug('rabbit: connection established');
1119
- this.oldCreatingConnection = false;
1120
- this.oldEm.emit(CONNECTION_CREATED_CONST, connection);
1121
- isResolved = true;
1122
- resolve(connection);
1123
- });
1124
- });
1125
- }
1126
-
1127
- private saveConsumerOld(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
1128
- const isConsumerExist :boolean = this.oldConsumers.some((consumer) => consumer.queue === queue);
1129
- if (!isConsumerExist) {
1130
- logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
1131
- this.oldConsumers.push({
1132
- queue,
1133
- callback,
1134
- options,
1135
- });
1136
- }
1137
- }
1138
-
1139
- async assertQueueOld(queueName: string, options?: Options.AssertQueue): Promise<any> {
1140
- RabbitMq.validateName('queue', queueName);
1141
- if (this.oldQueues[queueName]) {
1142
- delete this.oldQueueSetupPromises[queueName];
1143
- return this.oldQueues[queueName];
1144
- }
1145
-
1146
- if (this.oldQueueSetupPromises[queueName]) {
1147
- return this.oldQueueSetupPromises[queueName];
1148
- }
1149
-
1150
- this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
1151
- return this.oldQueueSetupPromises[queueName];
1152
- }
1153
-
1154
- async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
1155
- let queue: Replies.AssertQueue;
1156
- const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
1157
- const localeOptions = {
1158
- ...options,
1159
- durable: true,
1160
- arguments: {
1161
- ...options?.arguments,
1162
- 'x-consumer-timeout': 1000 * 60 * 60 * 24,
1163
- 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
1164
- },
1165
- };
1166
- try {
1167
- const channel: ChannelWrapper = await this.assertChannelOld();
1168
- debug('assertQueue->channel.addSetup', { queueName });
1169
- await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
1170
- debug('assertQueue->channel.assertQueue', { queueName });
1171
- queue = await channel.assertQueue(queueName, localeOptions);
1172
- } catch (e) {
1173
- logger.error('rabbit: assertQueue error', { queueName, options, error: e });
1174
- if (!this.options?.dontRetryAssert) {
1175
- debug('retrying assertQueue', { queueName });
1176
- const channel = await this.assertChannelOld({ force: true });
1177
- await this.deleteQueueOld(queueName);
1178
-
1179
- debug('retrying assertQueue->channel.addSetup', { queueName });
1180
- await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
1181
- debug('retrying assertQueue->channel.assertQueue', { queueName });
1182
- queue = await channel.assertQueue(queueName, localeOptions);
1183
- } else {
1184
- throw e;
1185
- }
1186
- }
1187
-
1188
- this.oldQueues[queueName] = queue;
1189
- return queue;
1190
- }
1191
-
1192
- async assertChannelOld({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
1193
- if (!this.oldPublishChannelSetupPromise) {
1194
- this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
1195
- if (this.oldChannel && !force) {
1196
- return resolve(this.oldChannel);
1197
- }
1198
-
1199
- try {
1200
- const channel = await this.getNewChannelOld({});
1201
- channel.on('error', (err) => {
1202
- logger.error('rabbit: channel error', { err });
1203
- });
1204
- this.oldChannel = channel;
1205
- resolve(channel);
1206
- } catch (e) {
1207
- reject(e);
1208
- }
1209
- });
1210
- }
1211
- return this.oldPublishChannelSetupPromise;
1212
- }
1213
-
1214
- private async deleteQueueOld(queue: string) {
1215
- RabbitMq.validateName('queue', queue);
1216
- const channel: ChannelWrapper = await this.assertChannelOld();
1217
- logger.info('rabbit: deleting queue', { queue });
1218
- const deleteQueueRes = await channel.deleteQueue(queue);
1219
- debug('queue deleted', deleteQueueRes);
1220
- return deleteQueueRes;
1221
- }
1222
-
1223
- async assertExchangeOld(exchangeName: string, options?: any) {
1224
- const channel: ChannelWrapper = await this.assertChannelOld();
1225
-
1226
- if (this.oldExchanges[exchangeName]) {
1227
- delete this.oldAssertExchangePromises[exchangeName];
1228
- return this.oldExchanges[exchangeName];
1229
- }
1230
-
1231
- if (this.oldAssertExchangePromises[exchangeName]) {
1232
- return this.oldAssertExchangePromises[exchangeName];
1233
- }
1234
-
1235
- this.oldAssertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
1236
- this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
1237
- return this.oldExchanges[exchangeName];
1238
- }
1239
807
  }
1240
808
 
1241
809
  export default RabbitMq;