@autofleet/rabbit 4.0.0-beta.0 → 4.0.1

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.
Files changed (55) hide show
  1. package/dist/index.d.ts +24 -17
  2. package/dist/index.js +303 -180
  3. package/dist/index.js.map +1 -0
  4. package/dist/lib/celery.js +1 -0
  5. package/dist/lib/celery.js.map +1 -0
  6. package/dist/lib/consts.d.ts +0 -2
  7. package/dist/lib/consts.js +2 -3
  8. package/dist/lib/consts.js.map +1 -0
  9. package/dist/lib/rabbitError.js +1 -0
  10. package/dist/lib/rabbitError.js.map +1 -0
  11. package/dist/lib/redis.js +1 -0
  12. package/dist/lib/redis.js.map +1 -0
  13. package/dist/lib/types.d.ts +8 -0
  14. package/dist/lib/types.js +1 -0
  15. package/dist/lib/types.js.map +1 -0
  16. package/dist/lib/utils.js +1 -0
  17. package/dist/lib/utils.js.map +1 -0
  18. package/dist/logger.js +1 -0
  19. package/dist/logger.js.map +1 -0
  20. package/dist/{mock.d.ts → mock/index.d.ts} +1 -1
  21. package/dist/{mock.js → mock/index.js} +2 -1
  22. package/dist/mock/index.js.map +1 -0
  23. package/dist/mock/vitest.d.ts +13 -0
  24. package/dist/mock/vitest.js +18 -0
  25. package/dist/mock/vitest.js.map +1 -0
  26. package/package.json +22 -16
  27. package/src/index.ts +360 -203
  28. package/src/lib/consts.ts +0 -2
  29. package/src/lib/types.ts +10 -0
  30. package/src/{mock.ts → mock/index.ts} +2 -2
  31. package/src/mock/vitest.ts +24 -0
  32. package/tsconfig.build.json +5 -0
  33. package/tsconfig.json +2 -2
  34. package/vitest.config.ts +17 -0
  35. package/coverage/clover.xml +0 -669
  36. package/coverage/coverage-final.json +0 -9
  37. package/coverage/lcov-report/base.css +0 -224
  38. package/coverage/lcov-report/block-navigation.js +0 -87
  39. package/coverage/lcov-report/favicon.png +0 -0
  40. package/coverage/lcov-report/index.html +0 -131
  41. package/coverage/lcov-report/prettify.css +0 -1
  42. package/coverage/lcov-report/prettify.js +0 -2
  43. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  44. package/coverage/lcov-report/sorter.js +0 -196
  45. package/coverage/lcov-report/src/index.html +0 -131
  46. package/coverage/lcov-report/src/index.ts.html +0 -3826
  47. package/coverage/lcov-report/src/lib/celery.ts.html +0 -352
  48. package/coverage/lcov-report/src/lib/consts.ts.html +0 -142
  49. package/coverage/lcov-report/src/lib/index.html +0 -191
  50. package/coverage/lcov-report/src/lib/rabbitError.ts.html +0 -103
  51. package/coverage/lcov-report/src/lib/redis.ts.html +0 -133
  52. package/coverage/lcov-report/src/lib/types.ts.html +0 -268
  53. package/coverage/lcov-report/src/lib/utils.ts.html +0 -142
  54. package/coverage/lcov-report/src/logger.ts.html +0 -100
  55. package/coverage/lcov.info +0 -1076
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
- /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars */
2
-
1
+ /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars,no-param-reassign */
3
2
  import { EventEmitter, once } from 'events';
4
3
  import { promisify } from 'util';
5
4
  import moment from 'moment';
@@ -14,15 +13,12 @@ import {
14
13
  getCurrentPayload, newTrace, traceTypes, createOrSetRabbitTrace, outbreak,
15
14
  } from '@autofleet/zehut';
16
15
  import { randomUUID } from 'node:crypto';
17
- import axios from 'axios';
18
16
  import logger from './logger';
19
17
  import RabbitError from './lib/rabbitError';
20
18
  import getRedisInstance, { RedisConfig } from './lib/redis';
21
19
  import { assertExchangeFanout, rand, wrapSetImmediate } from './lib/utils';
22
20
  import {
23
21
  AUTOMATION_ID_HEADER,
24
- CONNECTION_CREATED_CONST,
25
- CONNECTION_FAILED_CONST,
26
22
  DEFAULT_LOCK_TIMEOUT,
27
23
  DEFAULT_OPTIONS,
28
24
  RETRY_HEADER,
@@ -41,6 +37,7 @@ import {
41
37
  CONSUMER_DEFAULT_OPTIONS,
42
38
  QueueSetupPromisesDictionary,
43
39
  AssertExchangePromisesDictionary,
40
+ ConnectionData,
44
41
  } from './lib/types';
45
42
 
46
43
  // const debug = nodeDebug('af-rabbitmq')
@@ -48,6 +45,12 @@ const debug = logger.debug.bind(logger);
48
45
 
49
46
  const PUBLISH_TIMEOUT = 1000 * 10;
50
47
 
48
+ // TODO: [QUORUM-PHASE-3] Delete this env var
49
+ const {
50
+ DISABLE_QUORUM_QUEUES_CONSUME,
51
+ DISABLE_QUORUM_QUEUES_PUBLISH,
52
+ } = process.env;
53
+
51
54
  export interface IAfRabbitMq {
52
55
  ack: any;
53
56
  nack: any;
@@ -89,11 +92,13 @@ type newChannelOpts = {
89
92
  name?: string;
90
93
  onClose?: null | ((args: any | null) => void);
91
94
  options?: CreateChannelOpts | undefined;
95
+ connection: ConnectionData;
92
96
  };
93
97
 
94
98
  type assertChannelOpts = {
95
99
  channelName?: string;
96
100
  force?: boolean;
101
+ connection: ConnectionData;
97
102
  }
98
103
 
99
104
  type AfConsumer = {
@@ -146,13 +151,15 @@ class RabbitMq implements IAfRabbitMq {
146
151
 
147
152
  RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
148
153
 
149
- channel: ChannelWrapper | null;
154
+ publishChannel: ChannelWrapper | null;
150
155
 
151
156
  publishChannelSetupPromise: Promise<ChannelWrapper> | null;
152
157
 
153
158
  blockReconnect: boolean | null | undefined
154
159
 
155
- connection: AmqpConnectionManager | null | undefined
160
+ publishConnection: ConnectionData
161
+
162
+ consumeConnection: ConnectionData
156
163
 
157
164
  em: EventEmitter;
158
165
 
@@ -166,7 +173,7 @@ class RabbitMq implements IAfRabbitMq {
166
173
 
167
174
  assertExchangePromises: AssertExchangePromisesDictionary;
168
175
 
169
- options: AfRabbitOptions | undefined;
176
+ options: AfRabbitOptions;
170
177
 
171
178
  redisClient: any;
172
179
 
@@ -177,17 +184,20 @@ class RabbitMq implements IAfRabbitMq {
177
184
 
178
185
  private consumers: Array<AfConsumer> = [];
179
186
 
180
- private isVHostExist = false;
187
+ private doesVHostExist = false;
181
188
 
182
- // TODO: DELETE OLD PROPERTIES
189
+ private vhost = 'quorum-vhost';
183
190
 
184
- oldChannel: ChannelWrapper | null;
191
+ // TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
192
+ oldPublishChannel: ChannelWrapper | null;
185
193
 
186
194
  oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null;
187
195
 
188
196
  oldBlockReconnect: boolean | null | undefined
189
197
 
190
- oldConnection: AmqpConnectionManager | null | undefined
198
+ oldPublishConnection: ConnectionData
199
+
200
+ oldConsumeConnection: ConnectionData
191
201
 
192
202
  oldEm: EventEmitter;
193
203
 
@@ -207,9 +217,22 @@ class RabbitMq implements IAfRabbitMq {
207
217
 
208
218
  constructor(options: AfRabbitOptions = {}, redisConfig?: RedisConfig) {
209
219
  this.em = new EventEmitter();
210
- this.channel = null;
220
+ this.publishChannel = null;
211
221
  this.publishChannelSetupPromise = null;
212
- this.connection = null;
222
+ this.publishConnection = {
223
+ amqpConnection: null,
224
+ creatingConnection: false,
225
+ connectionCreatedEventName: 'publishConnectionCreated',
226
+ connectionFailedEventName: 'publishConnectionFailed',
227
+ blockReconnect: false,
228
+ };
229
+ this.consumeConnection = {
230
+ amqpConnection: null,
231
+ creatingConnection: false,
232
+ connectionCreatedEventName: 'consumeConnectionCreated',
233
+ connectionFailedEventName: 'consumeConnectionFailed',
234
+ blockReconnect: false,
235
+ };
213
236
  this.creatingConnection = false;
214
237
  this.exchanges = {};
215
238
  this.queues = {};
@@ -218,10 +241,6 @@ class RabbitMq implements IAfRabbitMq {
218
241
  this.consumers = [];
219
242
  this.options = options;
220
243
 
221
- if (!options?.vhost) {
222
- this.options.vhost = process.env.VHOST_NAME || 'quorum-vhost';
223
- }
224
-
225
244
  this.redisClient = redisConfig && getRedisInstance(redisConfig);
226
245
  if (this.redisClient) {
227
246
  this.redisLock = promisify(RedisLock(this.redisClient)) as RedisLockType;
@@ -237,11 +256,24 @@ class RabbitMq implements IAfRabbitMq {
237
256
  });
238
257
  }
239
258
 
240
- // TODO: DELETE OLD PROPERTIES
259
+ // TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
241
260
  this.oldEm = new EventEmitter();
242
- this.oldChannel = null;
261
+ this.oldPublishChannel = null;
243
262
  this.oldPublishChannelSetupPromise = null;
244
- this.oldConnection = null;
263
+ this.oldPublishConnection = {
264
+ amqpConnection: null,
265
+ creatingConnection: false,
266
+ connectionCreatedEventName: 'oldPublishConnectionCreated',
267
+ connectionFailedEventName: 'oldPublishConnectionFailed',
268
+ blockReconnect: false,
269
+ };
270
+ this.oldConsumeConnection = {
271
+ amqpConnection: null,
272
+ creatingConnection: false,
273
+ connectionCreatedEventName: 'oldConsumeConnectionCreated',
274
+ connectionFailedEventName: 'oldConsumeConnectionFailed',
275
+ blockReconnect: false,
276
+ };
245
277
  this.oldCreatingConnection = false;
246
278
  this.oldExchanges = {};
247
279
  this.oldQueues = {};
@@ -252,57 +284,57 @@ class RabbitMq implements IAfRabbitMq {
252
284
  }
253
285
 
254
286
  private assertVHost = async () => {
255
- if (this.isVHostExist) {
287
+ if (this.doesVHostExist) {
256
288
  return;
257
289
  }
258
290
 
259
- if (!this.options?.vhost) {
260
- throw new Error('vhost is not defined');
261
- }
262
-
263
- const { vhost } = this.options;
264
- const auth = {
265
- auth: {
266
- username: process.env.RABBITMQ_USERNAME || 'guest',
267
- password: process.env.RABBITMQ_PASSWORD || 'guest',
268
- },
291
+ const username = process.env.RABBITMQ_USERNAME || 'guest';
292
+ const password = process.env.RABBITMQ_PASSWORD || 'guest';
293
+ const credentials = Buffer.from(`${username}:${password}`).toString('base64');
294
+ const headers = {
295
+ Authorization: `Basic ${credentials}`,
296
+ 'Content-Type': 'application/json',
269
297
  };
270
- const rabbitHost = `http://${(this.options.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
298
+
299
+ const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
300
+
301
+ const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
271
302
 
272
303
  try {
273
- const response = await axios.get(`${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`, auth);
304
+ const response = await fetch(url, {
305
+ method: 'GET',
306
+ headers,
307
+ });
274
308
 
275
- if (response.status !== 200) {
276
- throw new Error('Failed to check vhost');
309
+ if (response.status === 200) {
310
+ this.doesVHostExist = true;
311
+ logger.info('Vhost exists', { vhost: this.vhost });
312
+ return;
277
313
  }
278
314
 
279
- this.isVHostExist = true;
280
- logger.info('Vhost exists', { vhost });
281
- } catch (error) {
282
- // If the vhost does not exist, create it
283
- if (error instanceof axios.AxiosError && error.response?.status === 404) {
284
- try {
285
- await axios.put(
286
- `${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`,
287
- {
288
- default_queue_type: 'quorum',
289
- },
290
- auth,
291
- );
292
-
293
- this.isVHostExist = true;
294
- logger.info('Vhost created', { vhost: this.options?.vhost });
295
- return;
296
- } catch (createError) {
297
- logger.error('Failed to create vhost', { error: createError });
298
- throw createError;
299
- }
315
+ if (response.status !== 404) {
316
+ logger.error('Failed to check vhost', { response });
317
+ throw new RabbitError('Failed to check vhost');
318
+ }
319
+
320
+ const createResponse = await fetch(url, {
321
+ method: 'PUT',
322
+ headers,
323
+ body: JSON.stringify({ default_queue_type: 'quorum' }),
324
+ });
325
+
326
+ if (!createResponse.ok) {
327
+ logger.error('Failed to create vhost', { response: createResponse });
328
+ throw new RabbitError('Failed to create vhost');
300
329
  }
301
330
 
302
- logger.error('Failed to check vhost', { error });
331
+ this.doesVHostExist = true;
332
+ logger.info('Vhost created', { vhost: this.vhost });
333
+ } catch (error) {
334
+ logger.error('Failed to check or create vhost', { error });
303
335
  throw error;
304
336
  }
305
- }
337
+ };
306
338
 
307
339
  private shouldConsumeMessageByTimestamp = async (msg: ConsumeMessageOrNull) => {
308
340
  if (msg) {
@@ -351,13 +383,13 @@ class RabbitMq implements IAfRabbitMq {
351
383
  if (
352
384
  !skipRetry
353
385
  && (
354
- !msg.properties.headers[RETRY_HEADER]
386
+ !msg.properties.headers?.[RETRY_HEADER]
355
387
  || parseInt(msg.properties.headers[RETRY_HEADER], 10) < options.retries
356
388
  )
357
389
  ) {
358
390
  await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
359
391
  ...msg.properties.headers,
360
- [RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
392
+ [RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
361
393
  ? msg.properties.headers[RETRY_HEADER] + 1
362
394
  : 1,
363
395
  });
@@ -365,7 +397,7 @@ class RabbitMq implements IAfRabbitMq {
365
397
  const deadQueue = `${queue}-dead`;
366
398
  await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
367
399
  ...msg.properties.headers,
368
- [RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
400
+ [RETRY_HEADER]: msg.properties.headers?.[RETRY_HEADER]
369
401
  ? msg.properties.headers[RETRY_HEADER] + 1
370
402
  : 1,
371
403
  });
@@ -379,30 +411,38 @@ class RabbitMq implements IAfRabbitMq {
379
411
  }
380
412
  }
381
413
 
382
- async getConnection() {
414
+ async getConnection(connection: ConnectionData) {
383
415
  return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
384
- if (this.blockReconnect) {
416
+ const {
417
+ amqpConnection: connectionLocal,
418
+ creatingConnection,
419
+ connectionCreatedEventName,
420
+ connectionFailedEventName,
421
+ blockReconnect,
422
+ } = connection;
423
+
424
+ if (blockReconnect) {
385
425
  debug('rabbit: block reconnect');
386
426
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
387
427
  // @ts-ignore
388
428
  return resolve();
389
429
  }
390
- if (this.connection !== null) {
391
- if (this.options?.disableReconnect || this.connection?.isConnected()) {
430
+ if (connectionLocal !== null) {
431
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
392
432
  debug('rabbit: connection - is connected');
393
433
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
394
434
  // @ts-ignore
395
- return resolve(this.connection);
435
+ return resolve(connectionLocal);
396
436
  }
397
437
  debug('rabbit: connection - reconnecting');
398
438
  }
399
- if (this.creatingConnection) {
439
+ if (creatingConnection) {
400
440
  debug('rabbit: creating connection emi');
401
- this.em.once(CONNECTION_CREATED_CONST, resolve);
402
- this.em.once(CONNECTION_FAILED_CONST, reject);
441
+ this.em.once(connectionCreatedEventName, resolve);
442
+ this.em.once(connectionFailedEventName, reject);
403
443
  return;
404
444
  }
405
- this.creatingConnection = true;
445
+ connection.creatingConnection = true;
406
446
  let isResolved = false;
407
447
 
408
448
  // It is import to use it as a function and not as a variable
@@ -414,65 +454,72 @@ class RabbitMq implements IAfRabbitMq {
414
454
  const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
415
455
 
416
456
  debug('rabbit: creating connection', { host, userName, HEARTBEAT });
417
- return [`amqp://${userName}:${password}@${host}/${this.options?.vhost}?heartbeat=${HEARTBEAT}`];
457
+ return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
418
458
  };
419
459
 
420
460
  const defaultUrls = findServers();
421
- const connection: AmqpConnectionManager = await connect(defaultUrls, {
461
+ const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
422
462
  findServers,
423
463
  });
424
464
 
425
- this.connection = connection;
426
- this.connection.on('error', (err) => {
465
+ connection.amqpConnection = newConnection;
466
+ newConnection.on('error', (err) => {
427
467
  logger.error('rabbit: connection error', { err });
428
468
  if (!isResolved) {
429
469
  isResolved = true;
430
470
  reject(err);
431
- this.em.emit(CONNECTION_FAILED_CONST, err);
471
+ this.em.emit(connectionFailedEventName, err);
432
472
  }
433
473
  });
434
474
 
435
- this.connection.on('connectFailed', (err) => {
475
+ newConnection.on('connectFailed', (err) => {
436
476
  this.consumersTags = [];
437
- logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.options?.vhost });
477
+ if (typeof err.url === 'string') {
478
+ err.url = this.maskURL(err.url);
479
+ }
480
+ logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
438
481
  if (!isResolved) {
439
482
  isResolved = true;
440
483
  reject(err);
441
- this.em.emit(CONNECTION_FAILED_CONST, err);
484
+ this.em.emit(connectionFailedEventName, err);
442
485
  }
443
486
  });
444
487
 
445
- this.connection.on('disconnect', ({ err }) => {
446
- // this.channel = null;
488
+ newConnection.on('disconnect', ({ err }) => {
447
489
  this.consumersTags = [];
448
490
  debug('rabbit: connection closed');
449
491
  if (this.options?.disableReconnect) {
450
492
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
451
- this.blockReconnect = true;
493
+ connection.blockReconnect = true;
452
494
  } else {
453
495
  logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
454
496
  }
455
497
  });
456
498
 
457
- this.connection.once('connect', async () => {
499
+ newConnection.once('connect', async () => {
458
500
  debug('rabbit: connection established');
459
- this.creatingConnection = false;
460
- this.em.emit(CONNECTION_CREATED_CONST, connection);
501
+ connection.creatingConnection = false;
502
+ this.em.emit(connectionCreatedEventName, newConnection);
461
503
  isResolved = true;
462
- resolve(connection);
504
+ resolve(newConnection);
463
505
  });
464
506
  });
465
507
  }
466
508
 
467
- async getNewChannel({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
468
- let connection!: AmqpConnectionManager;
509
+ async getNewChannel({
510
+ name = rand().toString(),
511
+ onClose = null,
512
+ options = {},
513
+ connection,
514
+ }: newChannelOpts) {
515
+ let localConnection!: AmqpConnectionManager;
469
516
  try {
470
- connection = await this.getConnection();
517
+ localConnection = await this.getConnection(connection);
471
518
  } catch (e) {
472
519
  logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
473
520
  throw e;
474
521
  }
475
- const channel = connection.createChannel({ ...options });
522
+ const channel = localConnection?.createChannel({ ...options });
476
523
  once(channel, 'close').then((args) => {
477
524
  logger.error(`rabbit: channel ${name} closed`);
478
525
  onClose?.(args);
@@ -487,19 +534,21 @@ class RabbitMq implements IAfRabbitMq {
487
534
  }
488
535
  }
489
536
 
490
- async assertChannel({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
537
+ async assertChannel({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
491
538
  if (!this.publishChannelSetupPromise) {
492
539
  this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
493
- if (this.channel && !force) {
494
- return resolve(this.channel);
540
+ if (this.publishChannel && !force) {
541
+ return resolve(this.publishChannel);
495
542
  }
496
543
 
497
544
  try {
498
- const channel = await this.getNewChannel({});
545
+ const channel = await this.getNewChannel({ connection });
499
546
  channel.on('error', (err) => {
500
547
  logger.error('rabbit: channel error', { err });
501
548
  });
502
- this.channel = channel;
549
+ if (this.publishConnection === connection) {
550
+ this.publishChannel = channel;
551
+ }
503
552
  resolve(channel);
504
553
  } catch (e) {
505
554
  reject(e);
@@ -509,8 +558,8 @@ class RabbitMq implements IAfRabbitMq {
509
558
  return this.publishChannelSetupPromise;
510
559
  }
511
560
 
512
- async assertExchange(exchangeName: string, options?: any) {
513
- const channel: ChannelWrapper = await this.assertChannel();
561
+ async assertExchange(exchangeName: string, connection: ConnectionData) {
562
+ const channel: ChannelWrapper = await this.assertChannel({ connection });
514
563
 
515
564
  if (this.exchanges[exchangeName]) {
516
565
  delete this.assertExchangePromises[exchangeName];
@@ -526,35 +575,34 @@ class RabbitMq implements IAfRabbitMq {
526
575
  return this.exchanges[exchangeName];
527
576
  }
528
577
 
529
- // TODO: Change the implementation to the new one
530
578
  async getQueueLength(queue: string) {
531
579
  RabbitMq.validateName('queue', queue);
532
- const { oldChannel: channel } = this;
580
+ const { publishChannel: channel } = this;
533
581
  if (!channel) {
534
- throw new Error('channel is not defined');
582
+ throw new RabbitError('channel is not defined');
535
583
  }
536
- debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
584
+ debug('rabbit: getting queue length', { queue, connected: this.publishConnection.amqpConnection?.isConnected() });
537
585
  return channel?.checkQueue(queue);
538
586
  }
539
587
 
540
- private async deleteQueue(queue: string) {
588
+ private async deleteQueue(queue: string, connection: ConnectionData) {
541
589
  RabbitMq.validateName('queue', queue);
542
- const channel: ChannelWrapper = await this.assertChannel();
590
+ const channel: ChannelWrapper = await this.assertChannel({ connection });
543
591
  logger.info('rabbit: deleting queue', { queue });
544
592
  const deleteQueueRes = await channel.deleteQueue(queue);
545
593
  debug('queue deleted', deleteQueueRes);
546
594
  return deleteQueueRes;
547
595
  }
548
596
 
549
- // TODO: Change the implementation to the new one
550
597
  async bindQueue(queue: string, exchange: string) {
551
- const channel: ChannelWrapper = await this.assertChannelOld();
598
+ const channel: ChannelWrapper = await this.assertChannel({ connection: this.publishConnection });
552
599
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
553
600
  return channel.bindQueue(queue, exchange, '');
554
601
  }
555
602
 
556
603
  async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
557
604
  let queue: Replies.AssertQueue;
605
+ const connection = this.publishConnection;
558
606
  const localeOptions = {
559
607
  ...options,
560
608
  durable: true,
@@ -565,7 +613,7 @@ class RabbitMq implements IAfRabbitMq {
565
613
  },
566
614
  };
567
615
  try {
568
- const channel: ChannelWrapper = await this.assertChannel();
616
+ const channel: ChannelWrapper = await this.assertChannel({ connection });
569
617
  debug('assertQueue->channel.addSetup', { queueName });
570
618
  await channel.addSetup(async (setupChannel: ConfirmChannel) => {
571
619
  await setupChannel.assertQueue(queueName, localeOptions);
@@ -576,8 +624,8 @@ class RabbitMq implements IAfRabbitMq {
576
624
  logger.error('rabbit: assertQueue error', { queueName, options, error: e });
577
625
  if (!this.options?.dontRetryAssert) {
578
626
  debug('retrying assertQueue', { queueName });
579
- const channel = await this.assertChannel({ force: true });
580
- await this.deleteQueue(queueName);
627
+ const channel = await this.assertChannel({ force: true, connection });
628
+ await this.deleteQueue(queueName, connection);
581
629
 
582
630
  debug('retrying assertQueue->channel.addSetup', { queueName });
583
631
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
@@ -592,7 +640,7 @@ class RabbitMq implements IAfRabbitMq {
592
640
  return queue;
593
641
  }
594
642
 
595
- // TODO: Can be deleted after deleting the old consumers
643
+ // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
596
644
  static shouldUseQuorum(queueName: string): boolean {
597
645
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
598
646
 
@@ -637,8 +685,8 @@ class RabbitMq implements IAfRabbitMq {
637
685
 
638
686
  // Used by the microservices to consume messages from the queue
639
687
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
640
- // TODO: USE THE IMPLEMENTATION OF THE NEW CONSUME AND DELETE THE NEW AND OLD
641
- if (options?.isQuorumQueue !== false) {
688
+ // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
689
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
642
690
  await this.assertVHost();
643
691
  await this.consumeNew(queue, callback, options);
644
692
  }
@@ -646,12 +694,12 @@ class RabbitMq implements IAfRabbitMq {
646
694
  await this.consumeOld(queue, callback, options);
647
695
  }
648
696
 
649
- // TODO: DELETE
697
+ // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
650
698
  async consumeNew(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
651
699
  await this.consumeFromRabbit(queue, callback, options);
652
700
  }
653
701
 
654
- // TODO: DELETE
702
+ // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
655
703
  async consumeOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
656
704
  await this.consumeFromRabbitOld(queue, callback, options);
657
705
  }
@@ -686,11 +734,11 @@ class RabbitMq implements IAfRabbitMq {
686
734
  } = optionsWithDefaults;
687
735
  if (useConsumeWithLock) {
688
736
  if (!this.redisLock) {
689
- throw new Error('Usage of consumeWithLock requires RedisInstance');
737
+ throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
690
738
  }
691
739
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
692
740
  }
693
- const channel = await this.getNewChannel({});
741
+ const channel = await this.getNewChannel({ connection: this.consumeConnection });
694
742
  return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
695
743
  const q = await this.assertQueue(queue, optionsWithDefaults);
696
744
  await confirmChannel.prefetch(limit, false);
@@ -701,9 +749,9 @@ class RabbitMq implements IAfRabbitMq {
701
749
  return null;
702
750
  }
703
751
 
704
- const traceId = msg.properties.headers[TRACING_HEADER];
705
- const userId = msg.properties.headers[USER_TRACING_HEADER];
706
- const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
752
+ const traceId = msg.properties.headers![TRACING_HEADER];
753
+ const userId = msg.properties.headers![USER_TRACING_HEADER];
754
+ const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
707
755
  const parsedMessage = RabbitMq.parseMsg(msg);
708
756
  const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
709
757
  const trace = newTrace(traceTypes.RABBIT);
@@ -786,10 +834,14 @@ class RabbitMq implements IAfRabbitMq {
786
834
  RabbitMq.validateName('exchange', exchange);
787
835
  RabbitMq.validateName('queue', queue);
788
836
  const { limit, deadMessageTtl } = optionsWithDefaults;
789
- if (options?.isQuorumQueue !== false) {
837
+ // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
838
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
790
839
  await this.assertVHost();
791
840
  await this.saveConsumer(queue, callback, options);
792
- const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
841
+ const channel: ChannelWrapper = await this.getNewChannel({
842
+ name: `consume-exchange-${exchange}-queue-${queue}`,
843
+ connection: this.consumeConnection,
844
+ });
793
845
 
794
846
  await channel.addSetup(async (c: ConfirmChannel) => {
795
847
  const assertExchange = await assertExchangeFanout(c, exchange);
@@ -806,10 +858,12 @@ class RabbitMq implements IAfRabbitMq {
806
858
  ]);
807
859
  });
808
860
  }
809
-
810
- // TODO: DELETE OLD
861
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
811
862
  await this.saveConsumerOld(queue, callback, options);
812
- const channelOld: ChannelWrapper = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
863
+ const channelOld: ChannelWrapper = await this.getNewChannelOld({
864
+ name: `consume-exchange-${exchange}-queue-${queue}-old`,
865
+ connection: this.oldConsumeConnection,
866
+ });
813
867
  await channelOld.addSetup(async (c: ConfirmChannel) => {
814
868
  const assertExchange = await assertExchangeFanout(c, exchange);
815
869
  await c.assertQueue(queue);
@@ -827,12 +881,25 @@ class RabbitMq implements IAfRabbitMq {
827
881
  }
828
882
 
829
883
  // Used by the microservices to publish messages to the exchange
830
- // TODO: Change the implementation to the new one
831
- async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
884
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
885
+ async publish(exchange: string, content: any, customHeaders?: any, isQuorumQueue = true) : Promise<boolean> {
886
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
887
+ return wrapSetImmediate(async () => {
888
+ await this.assertVHost();
889
+ RabbitMq.validateName('exchange', exchange);
890
+ const channel: ChannelWrapper = await this.assertChannel({ connection: this.publishConnection });
891
+ await this.assertExchange(exchange, this.publishConnection);
892
+ await channel.publish(exchange, '',
893
+ Buffer.from(JSON.stringify(content)),
894
+ RabbitMq.getPublishOptions(customHeaders));
895
+ });
896
+ }
897
+
898
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
832
899
  return wrapSetImmediate(async () => {
833
900
  RabbitMq.validateName('exchange', exchange);
834
- const channel: ChannelWrapper = await this.assertChannelOld();
835
- await this.assertExchangeOld(exchange);
901
+ const channel: ChannelWrapper = await this.assertChannelOld({ connection: this.oldPublishConnection });
902
+ await this.assertExchangeOld(exchange, this.oldPublishConnection);
836
903
  await channel.publish(exchange, '',
837
904
  Buffer.from(JSON.stringify(content)),
838
905
  RabbitMq.getPublishOptions(customHeaders));
@@ -840,65 +907,97 @@ class RabbitMq implements IAfRabbitMq {
840
907
  }
841
908
 
842
909
  // Used by the microservices to send messages to the queue
843
- // TODO: Change the implementation to the new one
910
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
844
911
  async sendToQueue(
845
912
  queue: string,
846
913
  content: any,
847
914
  options?: any,
848
915
  customHeaders?: any,
916
+ isQuorumQueue = true,
849
917
  ): Promise<boolean | undefined> {
850
- try {
851
- await this.assertChannelOld();
852
- } catch (e) {
853
- logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
854
- throw e;
855
- }
918
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
919
+ try {
920
+ await this.assertVHost();
921
+ await this.assertChannel({ connection: this.publishConnection });
922
+ } catch (e) {
923
+ logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
924
+ throw e;
925
+ }
856
926
 
857
- try {
858
- RabbitMq.validateName('queue', queue);
859
- await this.assertQueueOld(queue, options);
860
- } catch (e) {
861
- logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
862
- throw e;
863
- }
927
+ try {
928
+ RabbitMq.validateName('queue', queue);
929
+ await this.assertQueue(queue, options);
930
+ } catch (e) {
931
+ logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
932
+ throw e;
933
+ }
864
934
 
865
- try {
866
- const res = await this.oldChannel?.sendToQueue(queue,
867
- Buffer.from(JSON.stringify(content)),
868
- RabbitMq.getPublishOptions(customHeaders));
869
- debug(`rabbit: sending to queue ${queue}`, { res });
870
- return res;
871
- } catch (e) {
872
- const isConnected = await this.isConnected();
873
- logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
874
- throw e;
935
+ try {
936
+ const res = await this.publishChannel?.sendToQueue(queue,
937
+ Buffer.from(JSON.stringify(content)),
938
+ RabbitMq.getPublishOptions(customHeaders));
939
+ debug(`rabbit: sending to queue ${queue}`, { res });
940
+ return res;
941
+ } catch (e) {
942
+ const isConnected = await this.isConnected();
943
+ logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
944
+ throw e;
945
+ }
946
+ } else {
947
+ try {
948
+ await this.assertChannelOld({ connection: this.oldPublishConnection });
949
+ } catch (e) {
950
+ logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
951
+ throw e;
952
+ }
953
+
954
+ try {
955
+ RabbitMq.validateName('queue', queue);
956
+ await this.assertQueueOld(queue, options);
957
+ } catch (e) {
958
+ logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
959
+ throw e;
960
+ }
961
+
962
+ try {
963
+ const res = await this.oldPublishChannel?.sendToQueue(queue,
964
+ Buffer.from(JSON.stringify(content)),
965
+ RabbitMq.getPublishOptions(customHeaders));
966
+ debug(`rabbit: sending to queue ${queue}`, { res });
967
+ return res;
968
+ } catch (e) {
969
+ const isConnected = await this.isConnectedOld();
970
+ logger.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
971
+ throw e;
972
+ }
875
973
  }
876
974
  }
877
975
 
878
- // TODO: After changing the publish to the new implementation change the from the old to the new
879
- async isConnected() : Promise<boolean> {
880
- const connection = await this.getConnectionOld();
881
- const isConnected = connection.isConnected();
976
+ async isConnected(): Promise<boolean> {
977
+ debug('rabbit: start old is connected');
978
+ const consumeConnection = await this.getConnection(this.consumeConnection);
979
+ const publishConnection = await this.getConnection(this.publishConnection);
980
+ const isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
882
981
  if (!isConnected) {
883
- logger.error('rabbit: isConnected - false');
982
+ logger.error('rabbit: old isConnected - false');
884
983
  return false;
885
984
  }
886
- const channel: any = await this.assertChannelOld();
985
+ const channel: any = await this.assertChannel({ connection: this.publishConnection });
887
986
  try {
888
987
  await Promise.all([
889
988
  channel.waitForConnect(),
890
- ...this.oldConsumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
989
+ ...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
891
990
  ]);
892
991
  } catch (e) {
893
992
  logger.error('rabbit: isConnected - false');
894
993
  return false;
895
994
  }
896
- logger.info('rabbit: isConnected - true');
995
+ logger.debug('rabbit: isConnected - true');
897
996
  return true;
898
997
  }
899
998
 
900
999
  async gracefulShutdown(signal: string) : Promise<void> {
901
- // TODO: DELETE OLD
1000
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation they are not needed anymore
902
1001
  const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
903
1002
  logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
904
1003
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
@@ -925,11 +1024,11 @@ class RabbitMq implements IAfRabbitMq {
925
1024
  } = optionsWithDefaults;
926
1025
  if (useConsumeWithLock) {
927
1026
  if (!this.redisLock) {
928
- throw new Error('Usage of consumeWithLock requires RedisInstance');
1027
+ throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
929
1028
  }
930
1029
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
931
1030
  }
932
- const channel = await this.getNewChannelOld({});
1031
+ const channel = await this.getNewChannelOld({ connection: this.oldConsumeConnection });
933
1032
  return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
934
1033
  const q = await this.assertQueueOld(queue, optionsWithDefaults);
935
1034
  await confirmChannel.prefetch(limit, false);
@@ -940,9 +1039,9 @@ class RabbitMq implements IAfRabbitMq {
940
1039
  return null;
941
1040
  }
942
1041
 
943
- const traceId = msg.properties.headers[TRACING_HEADER];
944
- const userId = msg.properties.headers[USER_TRACING_HEADER];
945
- const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
1042
+ const traceId = msg.properties.headers![TRACING_HEADER];
1043
+ const userId = msg.properties.headers![USER_TRACING_HEADER];
1044
+ const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
946
1045
  const parsedMessage = RabbitMq.parseMsg(msg);
947
1046
  const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
948
1047
  const trace = newTrace(traceTypes.RABBIT);
@@ -1019,16 +1118,26 @@ class RabbitMq implements IAfRabbitMq {
1019
1118
  });
1020
1119
  }
1021
1120
 
1022
- // TODO: DELETE OLD PROPERTIES UNDER THIS LINE
1023
- async getNewChannelOld({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
1024
- let connection!: AmqpConnectionManager;
1121
+ // TODO: [QUORUM-PHASE-3] Delete all the function under this line.
1122
+ async getNewChannelOld({
1123
+ name = rand().toString(),
1124
+ onClose = null,
1125
+ options = {},
1126
+ connection,
1127
+ }: newChannelOpts) {
1128
+ let localConnection!: AmqpConnectionManager;
1025
1129
  try {
1026
- connection = await this.getConnectionOld();
1130
+ localConnection = await this.getConnectionOld(connection);
1027
1131
  } catch (e) {
1028
1132
  logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
1029
1133
  throw e;
1030
1134
  }
1031
- const channel = connection.createChannel({ ...options });
1135
+
1136
+ if (!localConnection) {
1137
+ throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
1138
+ }
1139
+
1140
+ const channel = localConnection?.createChannel({ ...options });
1032
1141
  once(channel, 'close').then((args) => {
1033
1142
  logger.error(`rabbit: channel ${name} closed`);
1034
1143
  onClose?.(args);
@@ -1043,30 +1152,38 @@ class RabbitMq implements IAfRabbitMq {
1043
1152
  }
1044
1153
  }
1045
1154
 
1046
- async getConnectionOld() {
1155
+ async getConnectionOld(connection: ConnectionData) {
1047
1156
  return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
1048
- if (this.oldBlockReconnect) {
1157
+ const {
1158
+ amqpConnection: connectionLocal,
1159
+ creatingConnection,
1160
+ connectionCreatedEventName,
1161
+ connectionFailedEventName,
1162
+ blockReconnect,
1163
+ } = connection;
1164
+
1165
+ if (blockReconnect) {
1049
1166
  debug('rabbit: block reconnect');
1050
1167
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1051
1168
  // @ts-ignore
1052
1169
  return resolve();
1053
1170
  }
1054
- if (this.oldConnection !== null) {
1055
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
1171
+ if (connectionLocal !== null) {
1172
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
1056
1173
  debug('rabbit: connection - is connected');
1057
1174
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1058
1175
  // @ts-ignore
1059
- return resolve(this.oldConnection);
1176
+ return resolve(connectionLocal);
1060
1177
  }
1061
1178
  debug('rabbit: connection - reconnecting');
1062
1179
  }
1063
- if (this.oldCreatingConnection) {
1180
+ if (creatingConnection) {
1064
1181
  debug('rabbit: creating connection emi');
1065
- this.oldEm.once(CONNECTION_CREATED_CONST, resolve);
1066
- this.oldEm.once(CONNECTION_FAILED_CONST, reject);
1182
+ this.oldEm.once(connectionCreatedEventName, resolve);
1183
+ this.oldEm.once(connectionFailedEventName, reject);
1067
1184
  return;
1068
1185
  }
1069
- this.oldCreatingConnection = true;
1186
+ connection.creatingConnection = true;
1070
1187
  let isResolved = false;
1071
1188
 
1072
1189
  // It is import to use it as a function and not as a variable
@@ -1083,47 +1200,50 @@ class RabbitMq implements IAfRabbitMq {
1083
1200
  };
1084
1201
 
1085
1202
  const defaultUrls = findServers();
1086
- const connection: AmqpConnectionManager = await connect(defaultUrls, {
1203
+ const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
1087
1204
  findServers,
1088
1205
  });
1089
1206
 
1090
- this.oldConnection = connection;
1091
- this.oldConnection.on('error', (err) => {
1207
+ connection.amqpConnection = newConnection;
1208
+ newConnection.on('error', (err) => {
1092
1209
  logger.error('rabbit: connection error', { err });
1093
1210
  if (!isResolved) {
1094
1211
  isResolved = true;
1095
1212
  reject(err);
1096
- this.oldEm.emit(CONNECTION_FAILED_CONST, err);
1213
+ this.oldEm.emit(connectionFailedEventName, err);
1097
1214
  }
1098
1215
  });
1099
1216
 
1100
- this.oldConnection.on('connectFailed', (err) => {
1217
+ newConnection.on('connectFailed', (err) => {
1101
1218
  this.oldConsumersTags = [];
1219
+ if (typeof err.url === 'string') {
1220
+ err.url = this.maskURL(err.url);
1221
+ }
1102
1222
  logger.error('rabbit: connection connectFailed', { err });
1103
1223
  if (!isResolved) {
1104
1224
  isResolved = true;
1105
1225
  reject(err);
1106
- this.oldEm.emit(CONNECTION_FAILED_CONST, err);
1226
+ this.oldEm.emit(connectionFailedEventName, err);
1107
1227
  }
1108
1228
  });
1109
1229
 
1110
- this.oldConnection.on('disconnect', ({ err }) => {
1230
+ newConnection.on('disconnect', ({ err }) => {
1111
1231
  this.oldConsumersTags = [];
1112
1232
  debug('rabbit: connection closed');
1113
1233
  if (this.options?.disableReconnect) {
1114
1234
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
1115
- this.oldBlockReconnect = true;
1235
+ connection.blockReconnect = true;
1116
1236
  } else {
1117
1237
  logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
1118
1238
  }
1119
1239
  });
1120
1240
 
1121
- this.oldConnection.once('connect', async () => {
1241
+ newConnection.once('connect', async () => {
1122
1242
  debug('rabbit: connection established');
1123
- this.oldCreatingConnection = false;
1124
- this.oldEm.emit(CONNECTION_CREATED_CONST, connection);
1243
+ connection.creatingConnection = false;
1244
+ this.oldEm.emit(connectionCreatedEventName, newConnection);
1125
1245
  isResolved = true;
1126
- resolve(connection);
1246
+ resolve(newConnection);
1127
1247
  });
1128
1248
  });
1129
1249
  }
@@ -1157,6 +1277,7 @@ class RabbitMq implements IAfRabbitMq {
1157
1277
 
1158
1278
  async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
1159
1279
  let queue: Replies.AssertQueue;
1280
+ const connection = this.oldPublishConnection;
1160
1281
  const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
1161
1282
  const localeOptions = {
1162
1283
  ...options,
@@ -1168,7 +1289,7 @@ class RabbitMq implements IAfRabbitMq {
1168
1289
  },
1169
1290
  };
1170
1291
  try {
1171
- const channel: ChannelWrapper = await this.assertChannelOld();
1292
+ const channel: ChannelWrapper = await this.assertChannelOld({ connection });
1172
1293
  debug('assertQueue->channel.addSetup', { queueName });
1173
1294
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
1174
1295
  debug('assertQueue->channel.assertQueue', { queueName });
@@ -1177,8 +1298,8 @@ class RabbitMq implements IAfRabbitMq {
1177
1298
  logger.error('rabbit: assertQueue error', { queueName, options, error: e });
1178
1299
  if (!this.options?.dontRetryAssert) {
1179
1300
  debug('retrying assertQueue', { queueName });
1180
- const channel = await this.assertChannelOld({ force: true });
1181
- await this.deleteQueueOld(queueName);
1301
+ const channel = await this.assertChannelOld({ force: true, connection });
1302
+ await this.deleteQueueOld(queueName, connection);
1182
1303
 
1183
1304
  debug('retrying assertQueue->channel.addSetup', { queueName });
1184
1305
  await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
@@ -1193,19 +1314,21 @@ class RabbitMq implements IAfRabbitMq {
1193
1314
  return queue;
1194
1315
  }
1195
1316
 
1196
- async assertChannelOld({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
1317
+ async assertChannelOld({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
1197
1318
  if (!this.oldPublishChannelSetupPromise) {
1198
1319
  this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
1199
- if (this.oldChannel && !force) {
1200
- return resolve(this.oldChannel);
1320
+ if (this.oldPublishChannel && !force) {
1321
+ return resolve(this.oldPublishChannel);
1201
1322
  }
1202
1323
 
1203
1324
  try {
1204
- const channel = await this.getNewChannelOld({});
1325
+ const channel = await this.getNewChannelOld({ connection });
1205
1326
  channel.on('error', (err) => {
1206
1327
  logger.error('rabbit: channel error', { err });
1207
1328
  });
1208
- this.oldChannel = channel;
1329
+ if (this.oldPublishConnection === connection) {
1330
+ this.oldPublishChannel = channel;
1331
+ }
1209
1332
  resolve(channel);
1210
1333
  } catch (e) {
1211
1334
  reject(e);
@@ -1215,17 +1338,17 @@ class RabbitMq implements IAfRabbitMq {
1215
1338
  return this.oldPublishChannelSetupPromise;
1216
1339
  }
1217
1340
 
1218
- private async deleteQueueOld(queue: string) {
1341
+ private async deleteQueueOld(queue: string, connection: ConnectionData) {
1219
1342
  RabbitMq.validateName('queue', queue);
1220
- const channel: ChannelWrapper = await this.assertChannelOld();
1343
+ const channel: ChannelWrapper = await this.assertChannelOld({ connection });
1221
1344
  logger.info('rabbit: deleting queue', { queue });
1222
1345
  const deleteQueueRes = await channel.deleteQueue(queue);
1223
1346
  debug('queue deleted', deleteQueueRes);
1224
1347
  return deleteQueueRes;
1225
1348
  }
1226
1349
 
1227
- async assertExchangeOld(exchangeName: string, options?: any) {
1228
- const channel: ChannelWrapper = await this.assertChannelOld();
1350
+ async assertExchangeOld(exchangeName: string, connection: ConnectionData) {
1351
+ const channel: ChannelWrapper = await this.assertChannelOld({ connection });
1229
1352
 
1230
1353
  if (this.oldExchanges[exchangeName]) {
1231
1354
  delete this.oldAssertExchangePromises[exchangeName];
@@ -1240,6 +1363,40 @@ class RabbitMq implements IAfRabbitMq {
1240
1363
  this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
1241
1364
  return this.oldExchanges[exchangeName];
1242
1365
  }
1366
+
1367
+ async isConnectedOld() : Promise<boolean> {
1368
+ debug('rabbit: start old is connected');
1369
+ const oldConsumeConnection = await this.getConnectionOld(this.oldConsumeConnection);
1370
+ const oldPublishConnection = await this.getConnectionOld(this.oldPublishConnection);
1371
+ const oldIsConnected = oldConsumeConnection.isConnected() && oldPublishConnection.isConnected();
1372
+ if (!oldIsConnected) {
1373
+ logger.error('rabbit: old isConnected - false');
1374
+ return false;
1375
+ }
1376
+ const oldChannel: any = await this.assertChannelOld({ connection: this.oldPublishConnection });
1377
+ try {
1378
+ await Promise.all([
1379
+ oldChannel.waitForConnect(),
1380
+ ...this.oldConsumers.map((c: AfConsumer) => oldChannel.checkQueue(c.queue)),
1381
+ ]);
1382
+ } catch (e) {
1383
+ logger.error('rabbit: old isConnected - false');
1384
+ return false;
1385
+ }
1386
+ logger.debug('rabbit: old isConnected - true');
1387
+ return true;
1388
+ }
1389
+
1390
+ private maskURL = (url: string): string => {
1391
+ try {
1392
+ const urlObj = new URL(url);
1393
+ urlObj.username = '***';
1394
+ urlObj.password = '***';
1395
+ return urlObj.toString();
1396
+ } catch {
1397
+ return url;
1398
+ }
1399
+ }
1243
1400
  }
1244
1401
 
1245
1402
  export default RabbitMq;