@autofleet/rabbit 3.3.2 → 3.3.22-connection-test-beta

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/dist/index.js CHANGED
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.sendCeleryTaskViaHttp = void 0;
8
7
  const events_1 = require("events");
9
8
  const util_1 = require("util");
10
9
  const moment_1 = __importDefault(require("moment"));
@@ -22,6 +21,38 @@ const types_1 = require("./lib/types");
22
21
  const debug = logger_1.default.debug.bind(logger_1.default);
23
22
  const PUBLISH_TIMEOUT = 1000 * 10;
24
23
  const HEARTBEAT = '60';
24
+ const withTimeout = async (promise, timeoutMs) => new Promise((resolve, reject) => {
25
+ const timer = setTimeout(() => {
26
+ reject(new Error(`Promise timed out after ${timeoutMs} ms`));
27
+ }, timeoutMs);
28
+ promise
29
+ .then((value) => {
30
+ clearTimeout(timer);
31
+ resolve(value);
32
+ })
33
+ .catch((err) => {
34
+ clearTimeout(timer);
35
+ reject(err);
36
+ });
37
+ });
38
+ const withRetry = async (operation, retries, timeoutMs) => new Promise(async (resolve, reject) => {
39
+ let lastError;
40
+ for (let attempt = 1; attempt <= retries; attempt += 1) {
41
+ try {
42
+ // eslint-disable-next-line no-await-in-loop
43
+ const result = await withTimeout(operation(), timeoutMs);
44
+ return resolve(result);
45
+ }
46
+ catch (err) {
47
+ lastError = err;
48
+ logger_1.default.error(`Attempt ${attempt} failed: ${err}`);
49
+ if (attempt < retries) {
50
+ logger_1.default.info(`Retrying (${attempt}/${retries})...`);
51
+ }
52
+ }
53
+ }
54
+ reject(lastError);
55
+ });
25
56
  class RabbitMq {
26
57
  static parseMsg(msg) {
27
58
  let { content } = msg;
@@ -56,57 +87,10 @@ class RabbitMq {
56
87
  },
57
88
  };
58
89
  }
59
- constructor(options = {}, redisConfig) {
90
+ constructor(options, redisConfig) {
60
91
  this.DISCONNECT_MSG = 'rabbit: connection disconnect';
61
92
  this.RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
62
93
  this.consumers = [];
63
- this.doesVHostExist = false;
64
- this.vhost = 'quorum-vhost';
65
- this.oldConsumers = [];
66
- this.assertVHost = async () => {
67
- if (this.doesVHostExist) {
68
- return;
69
- }
70
- const username = process.env.RABBITMQ_USERNAME || 'guest';
71
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
72
- const credentials = Buffer.from(`${username}:${password}`).toString('base64');
73
- const headers = {
74
- Authorization: `Basic ${credentials}`,
75
- 'Content-Type': 'application/json',
76
- };
77
- const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
78
- const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
79
- try {
80
- const response = await fetch(url, {
81
- method: 'GET',
82
- headers,
83
- });
84
- if (response.status === 200) {
85
- this.doesVHostExist = true;
86
- logger_1.default.info('Vhost exists', { vhost: this.vhost });
87
- return;
88
- }
89
- if (response.status !== 404) {
90
- logger_1.default.error('Failed to check vhost', { response });
91
- throw new rabbitError_1.default('Failed to check vhost');
92
- }
93
- const createResponse = await fetch(url, {
94
- method: 'PUT',
95
- headers,
96
- body: JSON.stringify({ default_queue_type: 'quorum' }),
97
- });
98
- if (!createResponse.ok) {
99
- logger_1.default.error('Failed to create vhost', { response: createResponse });
100
- throw new rabbitError_1.default('Failed to create vhost');
101
- }
102
- this.doesVHostExist = true;
103
- logger_1.default.info('Vhost created', { vhost: this.vhost });
104
- }
105
- catch (error) {
106
- logger_1.default.error('Failed to check or create vhost', { error });
107
- throw error;
108
- }
109
- };
110
94
  this.shouldConsumeMessageByTimestamp = async (msg) => {
111
95
  if (msg) {
112
96
  const { properties: { headers } } = msg;
@@ -136,11 +120,11 @@ class RabbitMq {
136
120
  await this.unlockRedisIfNeeded(releaseLock);
137
121
  if (channel && msg) {
138
122
  if (!skipRetry
139
- && (!msg.properties.headers?.[consts_1.RETRY_HEADER]
123
+ && (!msg.properties.headers[consts_1.RETRY_HEADER]
140
124
  || parseInt(msg.properties.headers[consts_1.RETRY_HEADER], 10) < options.retries)) {
141
125
  await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
142
126
  ...msg.properties.headers,
143
- [consts_1.RETRY_HEADER]: msg.properties.headers?.[consts_1.RETRY_HEADER]
127
+ [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
144
128
  ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
145
129
  : 1,
146
130
  });
@@ -149,7 +133,7 @@ class RabbitMq {
149
133
  const deadQueue = `${queue}-dead`;
150
134
  await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
151
135
  ...msg.properties.headers,
152
- [consts_1.RETRY_HEADER]: msg.properties.headers?.[consts_1.RETRY_HEADER]
136
+ [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
153
137
  ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
154
138
  : 1,
155
139
  });
@@ -163,17 +147,6 @@ class RabbitMq {
163
147
  });
164
148
  }
165
149
  };
166
- this.maskURL = (url) => {
167
- try {
168
- const urlObj = new URL(url);
169
- urlObj.username = '***';
170
- urlObj.password = '***';
171
- return urlObj.toString();
172
- }
173
- catch {
174
- return url;
175
- }
176
- };
177
150
  this.em = new events_1.EventEmitter();
178
151
  this.channel = null;
179
152
  this.publishChannelSetupPromise = null;
@@ -199,18 +172,6 @@ class RabbitMq {
199
172
  await this.gracefulShutdown('SIGINT');
200
173
  });
201
174
  }
202
- // TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
203
- this.oldEm = new events_1.EventEmitter();
204
- this.oldChannel = null;
205
- this.oldPublishChannelSetupPromise = null;
206
- this.oldConnection = null;
207
- this.oldCreatingConnection = false;
208
- this.oldExchanges = {};
209
- this.oldQueues = {};
210
- this.oldQueueSetupPromises = {};
211
- this.oldAssertExchangePromises = {};
212
- this.oldConsumers = [];
213
- this.oldConsumersTags = [];
214
175
  }
215
176
  async getConnection() {
216
177
  return new Promise(async (resolve, reject) => {
@@ -245,7 +206,7 @@ class RabbitMq {
245
206
  const password = process.env.RABBITMQ_PASSWORD || 'guest';
246
207
  const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
247
208
  debug('rabbit: creating connection', { host, userName, HEARTBEAT });
248
- return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
209
+ return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
249
210
  };
250
211
  const defaultUrls = findServers();
251
212
  const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
@@ -262,10 +223,7 @@ class RabbitMq {
262
223
  });
263
224
  this.connection.on('connectFailed', (err) => {
264
225
  this.consumersTags = [];
265
- if (typeof err.url === 'string') {
266
- err.url = this.maskURL(err.url);
267
- }
268
- logger_1.default.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
226
+ logger_1.default.error('rabbit: connection connectFailed', { err });
269
227
  if (!isResolved) {
270
228
  isResolved = true;
271
229
  reject(err);
@@ -351,12 +309,11 @@ class RabbitMq {
351
309
  this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
352
310
  return this.exchanges[exchangeName];
353
311
  }
354
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
355
312
  async getQueueLength(queue) {
356
313
  RabbitMq.validateName('queue', queue);
357
- const { oldChannel: channel } = this;
314
+ const { channel } = this;
358
315
  if (!channel) {
359
- throw new rabbitError_1.default('channel is not defined');
316
+ throw new Error('channel is not defined');
360
317
  }
361
318
  debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
362
319
  return channel?.checkQueue(queue);
@@ -369,29 +326,27 @@ class RabbitMq {
369
326
  debug('queue deleted', deleteQueueRes);
370
327
  return deleteQueueRes;
371
328
  }
372
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
373
329
  async bindQueue(queue, exchange) {
374
- const channel = await this.assertChannelOld();
330
+ const channel = await this.assertChannel();
375
331
  await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
376
332
  return channel.bindQueue(queue, exchange, '');
377
333
  }
378
334
  async setupQueue(queueName, options) {
379
335
  let queue;
336
+ const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
380
337
  const localeOptions = {
381
338
  ...options,
382
339
  durable: true,
383
340
  arguments: {
384
341
  ...options?.arguments,
385
342
  'x-consumer-timeout': 1000 * 60 * 60 * 24,
386
- 'x-queue-type': 'quorum',
343
+ 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
387
344
  },
388
345
  };
389
346
  try {
390
347
  const channel = await this.assertChannel();
391
348
  debug('assertQueue->channel.addSetup', { queueName });
392
- await channel.addSetup(async (setupChannel) => {
393
- await setupChannel.assertQueue(queueName, localeOptions);
394
- });
349
+ await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
395
350
  debug('assertQueue->channel.assertQueue', { queueName });
396
351
  queue = await channel.assertQueue(queueName, localeOptions);
397
352
  }
@@ -413,7 +368,6 @@ class RabbitMq {
413
368
  this.queues[queueName] = queue;
414
369
  return queue;
415
370
  }
416
- // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
417
371
  static shouldUseQuorum(queueName) {
418
372
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
419
373
  if (envQuorumQueuesWhitelist === '*') {
@@ -448,23 +402,9 @@ class RabbitMq {
448
402
  });
449
403
  }
450
404
  }
451
- // Used by the microservices to consume messages from the queue
452
405
  async consume(queue, callback, options) {
453
- // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
454
- if (options?.isQuorumQueue !== false) {
455
- await this.assertVHost();
456
- await this.consumeNew(queue, callback, options);
457
- }
458
- await this.consumeOld(queue, callback, options);
459
- }
460
- // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
461
- async consumeNew(queue, callback, options) {
462
406
  await this.consumeFromRabbit(queue, callback, options);
463
407
  }
464
- // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
465
- async consumeOld(queue, callback, options) {
466
- await this.consumeFromRabbitOld(queue, callback, options);
467
- }
468
408
  async lockRedisIfNeeded(msg, options) {
469
409
  const { properties: { headers } } = msg;
470
410
  const timestamp = headers?.creationTimestamp;
@@ -487,7 +427,7 @@ class RabbitMq {
487
427
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
488
428
  if (useConsumeWithLock) {
489
429
  if (!this.redisLock) {
490
- throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
430
+ throw new Error('Usage of consumeWithLock requires RedisInstance');
491
431
  }
492
432
  logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
493
433
  }
@@ -569,57 +509,35 @@ class RabbitMq {
569
509
  }
570
510
  });
571
511
  }
572
- // Used by the microservices to consume messages from the exchange
573
512
  async consumeFromExchange(queue, exchange, callback, options) {
574
513
  const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
575
514
  RabbitMq.validateName('exchange', exchange);
576
515
  RabbitMq.validateName('queue', queue);
577
516
  const { limit, deadMessageTtl } = optionsWithDefaults;
578
- // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
579
- if (options?.isQuorumQueue !== false) {
580
- await this.assertVHost();
581
- await this.saveConsumer(queue, callback, options);
582
- const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
583
- await channel.addSetup(async (c) => {
584
- const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
585
- await c.assertQueue(queue);
586
- this.exchanges[exchange] = assertExchange;
587
- await c.prefetch(limit, false);
588
- return Promise.all([
589
- c.bindQueue(queue, exchange, ''),
590
- this.consumeNew(queue, callback, options),
591
- ]);
592
- });
593
- }
594
- // TODO: [QUORUM-PHASE-3] Delete the old implementation
595
- await this.saveConsumerOld(queue, callback, options);
596
- const channelOld = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
597
- await channelOld.addSetup(async (c) => {
517
+ await this.saveConsumer(queue, callback, options);
518
+ const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
519
+ return channel.addSetup(async (c) => {
598
520
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
599
521
  await c.assertQueue(queue);
600
- this.oldExchanges[exchange] = assertExchange;
601
- await c.prefetch(limit, false);
522
+ this.exchanges[exchange] = assertExchange;
523
+ await c.prefetch(limit, true);
602
524
  return Promise.all([
603
525
  c.bindQueue(queue, exchange, ''),
604
- this.consumeOld(queue, callback, options),
526
+ this.consume(queue, callback, options),
605
527
  ]);
606
528
  });
607
529
  }
608
- // Used by the microservices to publish messages to the exchange
609
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
610
530
  async publish(exchange, content, customHeaders) {
611
531
  return (0, utils_1.wrapSetImmediate)(async () => {
612
532
  RabbitMq.validateName('exchange', exchange);
613
- const channel = await this.assertChannelOld();
614
- await this.assertExchangeOld(exchange);
533
+ const channel = await this.assertChannel();
534
+ await this.assertExchange(exchange);
615
535
  await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
616
536
  });
617
537
  }
618
- // Used by the microservices to send messages to the queue
619
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
620
538
  async sendToQueue(queue, content, options, customHeaders) {
621
539
  try {
622
- await this.assertChannelOld();
540
+ await this.assertChannel();
623
541
  }
624
542
  catch (e) {
625
543
  logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
@@ -627,14 +545,14 @@ class RabbitMq {
627
545
  }
628
546
  try {
629
547
  RabbitMq.validateName('queue', queue);
630
- await this.assertQueueOld(queue, options);
548
+ await this.assertQueue(queue, options);
631
549
  }
632
550
  catch (e) {
633
551
  logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
634
552
  throw e;
635
553
  }
636
554
  try {
637
- const res = await this.oldChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
555
+ const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
638
556
  debug(`rabbit: sending to queue ${queue}`, { res });
639
557
  return res;
640
558
  }
@@ -644,38 +562,59 @@ class RabbitMq {
644
562
  throw e;
645
563
  }
646
564
  }
647
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
648
565
  async isConnected() {
649
- const connection = await this.getConnectionOld();
650
- const isConnected = connection.isConnected();
651
- if (!isConnected) {
652
- logger_1.default.error('rabbit: isConnected - false');
653
- return false;
654
- }
655
- const channel = await this.assertChannelOld();
656
566
  try {
657
- await Promise.all([
658
- channel.waitForConnect(),
659
- ...this.oldConsumers.map((c) => channel.checkQueue(c.queue)),
660
- ]);
567
+ const connection = await this.getConnection();
568
+ if (!connection.isConnected()) {
569
+ logger_1.default.error('rabbit: isConnected - false');
570
+ return false;
571
+ }
572
+ const channel = await this.assertChannel();
573
+ const timeoutMs = 5000;
574
+ const retries = 2;
575
+ const chunkSize = 10;
576
+ const processChunks = async (consumers) => {
577
+ for (let i = 0; i < consumers.length; i += chunkSize) {
578
+ const chunk = consumers.slice(i, i + chunkSize);
579
+ // eslint-disable-next-line no-await-in-loop
580
+ const chunkResults = await Promise.all(chunk.map((c) => withRetry(() => channel.checkQueue(c.queue), retries, timeoutMs).catch((err) => {
581
+ logger_1.default.error(`rabbit: Error in isConnected (checkQueue) - ${err.message}`);
582
+ return null;
583
+ })));
584
+ if (chunkResults.some((res) => res === null)) {
585
+ return false;
586
+ }
587
+ }
588
+ return true;
589
+ };
590
+ const waitForConnectResult = await withRetry(() => channel.waitForConnect(), retries, timeoutMs).catch((err) => {
591
+ logger_1.default.error(`rabbit: Error in isConnected (waitForConnect) - ${err.message}`);
592
+ return null;
593
+ });
594
+ if (waitForConnectResult === null) {
595
+ logger_1.default.error('rabbit: isConnected - false due to failed waitForConnect');
596
+ return false;
597
+ }
598
+ const allConsumersConnected = await processChunks(this.consumers);
599
+ if (!allConsumersConnected) {
600
+ logger_1.default.error('rabbit: isConnected - false due to failed consumer checks');
601
+ return false;
602
+ }
603
+ logger_1.default.info('rabbit: isConnected - true');
604
+ return true;
661
605
  }
662
606
  catch (e) {
663
- logger_1.default.error('rabbit: isConnected - false');
607
+ logger_1.default.error(`rabbit: isConnected - Exception occurred: ${e}`);
664
608
  return false;
665
609
  }
666
- logger_1.default.info('rabbit: isConnected - true');
667
- return true;
668
610
  }
669
611
  async gracefulShutdown(signal) {
670
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
671
- const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
612
+ const tagsNumber = this.consumersTags.length;
672
613
  logger_1.default.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
673
614
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
674
- const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
675
615
  // Clean the array to avoid race
676
616
  this.consumersTags = [];
677
- this.oldConsumersTags = [];
678
- const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
617
+ const results = await Promise.allSettled(cancelTagPromises);
679
618
  const rejected = results.filter((p) => p.status === 'rejected');
680
619
  if (rejected.length > 0) {
681
620
  logger_1.default.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
@@ -684,305 +623,5 @@ class RabbitMq {
684
623
  logger_1.default.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
685
624
  }
686
625
  }
687
- async consumeFromRabbitOld(queue, callback, options) {
688
- const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
689
- RabbitMq.validateName('queue', queue);
690
- this.saveConsumerOld(queue, callback, options);
691
- const uniqueId = (0, node_crypto_1.randomUUID)();
692
- const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
693
- if (useConsumeWithLock) {
694
- if (!this.redisLock) {
695
- throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
696
- }
697
- logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
698
- }
699
- const channel = await this.getNewChannelOld({});
700
- return channel.addSetup(async (confirmChannel) => {
701
- const q = await this.assertQueueOld(queue, optionsWithDefaults);
702
- await confirmChannel.prefetch(limit, false);
703
- const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
704
- if (!msg) {
705
- return null;
706
- }
707
- const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
708
- const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
709
- const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
710
- const parsedMessage = RabbitMq.parseMsg(msg);
711
- const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
712
- const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
713
- // setting also outbreak trace as part of legacy code
714
- const outbreakTrace = zehut_1.outbreak.newTrace(zehut_1.traceTypes.RABBIT);
715
- // enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
716
- // and we don't want to fail the flow because of it
717
- if (userId && enableRabbitTrace) {
718
- try {
719
- await Promise.all([
720
- (0, zehut_1.createOrSetRabbitTrace)(trace, userId),
721
- (0, zehut_1.createOrSetRabbitTrace)(outbreakTrace, userId),
722
- ]);
723
- }
724
- catch (e) {
725
- logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
726
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
727
- }
728
- }
729
- if (traceId) {
730
- trace?.context?.set(consts_1.TRACING_HEADER, traceId);
731
- outbreakTrace?.context.set(consts_1.TRACING_HEADER, traceId);
732
- }
733
- if (auditContext) {
734
- await auditContext(queue, {
735
- userId,
736
- automationId,
737
- });
738
- }
739
- const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
740
- if (!shouldConsume) {
741
- await this.unlockRedisIfNeeded(releaseLock);
742
- return this.ack(confirmChannel, msg)(msg);
743
- }
744
- let messageAcked = false;
745
- // setting the localAck function to be used in the callback
746
- const localAck = async () => {
747
- if (messageAcked) {
748
- return;
749
- }
750
- messageAcked = true;
751
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
752
- };
753
- const localNack = async (_, nackOptions = {}) => {
754
- if (messageAcked) {
755
- return;
756
- }
757
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
758
- messageAcked = true;
759
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
760
- };
761
- try {
762
- await callback(parsedMessage, localAck, localNack);
763
- }
764
- catch (e) {
765
- await localNack(msg);
766
- }
767
- }, types_1.CONSUMER_DEFAULT_OPTIONS);
768
- if (!consumerTag) {
769
- logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
770
- }
771
- else {
772
- logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
773
- this.oldConsumersTags.push([confirmChannel, consumerTag]);
774
- }
775
- });
776
- }
777
- // TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
778
- async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
779
- let connection;
780
- try {
781
- connection = await this.getConnectionOld();
782
- }
783
- catch (e) {
784
- logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
785
- throw e;
786
- }
787
- const channel = connection.createChannel({ ...options });
788
- (0, events_1.once)(channel, 'close').then((args) => {
789
- logger_1.default.error(`rabbit: channel ${name} closed`);
790
- onClose?.(args);
791
- });
792
- try {
793
- await (0, events_1.once)(channel, 'connect');
794
- debug(`rabbit: channel ${name} CONNECTED`);
795
- return channel;
796
- }
797
- catch (err) {
798
- logger_1.default.error(`rabbit: channel error ${name} error`, { err });
799
- throw err;
800
- }
801
- }
802
- async getConnectionOld() {
803
- return new Promise(async (resolve, reject) => {
804
- if (this.oldBlockReconnect) {
805
- debug('rabbit: block reconnect');
806
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
807
- // @ts-ignore
808
- return resolve();
809
- }
810
- if (this.oldConnection !== null) {
811
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
812
- debug('rabbit: connection - is connected');
813
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
814
- // @ts-ignore
815
- return resolve(this.oldConnection);
816
- }
817
- debug('rabbit: connection - reconnecting');
818
- }
819
- if (this.oldCreatingConnection) {
820
- debug('rabbit: creating connection emi');
821
- this.oldEm.once(consts_1.CONNECTION_CREATED_CONST, resolve);
822
- this.oldEm.once(consts_1.CONNECTION_FAILED_CONST, reject);
823
- return;
824
- }
825
- this.oldCreatingConnection = true;
826
- let isResolved = false;
827
- // It is import to use it as a function and not as a variable
828
- // because of k8s changes the env variables
829
- // and we want to use the new values
830
- const findServers = () => {
831
- const userName = process.env.RABBITMQ_USERNAME || 'guest';
832
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
833
- const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
834
- debug('rabbit: creating connection', { host, userName, HEARTBEAT });
835
- return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
836
- };
837
- const defaultUrls = findServers();
838
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
839
- findServers,
840
- });
841
- this.oldConnection = connection;
842
- this.oldConnection.on('error', (err) => {
843
- logger_1.default.error('rabbit: connection error', { err });
844
- if (!isResolved) {
845
- isResolved = true;
846
- reject(err);
847
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
848
- }
849
- });
850
- this.oldConnection.on('connectFailed', (err) => {
851
- this.oldConsumersTags = [];
852
- if (typeof err.url === 'string') {
853
- err.url = this.maskURL(err.url);
854
- }
855
- logger_1.default.error('rabbit: connection connectFailed', { err });
856
- if (!isResolved) {
857
- isResolved = true;
858
- reject(err);
859
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
860
- }
861
- });
862
- this.oldConnection.on('disconnect', ({ err }) => {
863
- this.oldConsumersTags = [];
864
- debug('rabbit: connection closed');
865
- if (this.options?.disableReconnect) {
866
- logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
867
- this.oldBlockReconnect = true;
868
- }
869
- else {
870
- logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
871
- }
872
- });
873
- this.oldConnection.once('connect', async () => {
874
- debug('rabbit: connection established');
875
- this.oldCreatingConnection = false;
876
- this.oldEm.emit(consts_1.CONNECTION_CREATED_CONST, connection);
877
- isResolved = true;
878
- resolve(connection);
879
- });
880
- });
881
- }
882
- saveConsumerOld(queue, callback, options) {
883
- const isConsumerExist = this.oldConsumers.some((consumer) => consumer.queue === queue);
884
- if (!isConsumerExist) {
885
- logger_1.default.info(`rabbit: consumer: ${queue} saved in consumer array`);
886
- this.oldConsumers.push({
887
- queue,
888
- callback,
889
- options,
890
- });
891
- }
892
- }
893
- async assertQueueOld(queueName, options) {
894
- RabbitMq.validateName('queue', queueName);
895
- if (this.oldQueues[queueName]) {
896
- delete this.oldQueueSetupPromises[queueName];
897
- return this.oldQueues[queueName];
898
- }
899
- if (this.oldQueueSetupPromises[queueName]) {
900
- return this.oldQueueSetupPromises[queueName];
901
- }
902
- this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
903
- return this.oldQueueSetupPromises[queueName];
904
- }
905
- async setupQueueOld(queueName, options) {
906
- let queue;
907
- const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
908
- const localeOptions = {
909
- ...options,
910
- durable: true,
911
- arguments: {
912
- ...options?.arguments,
913
- 'x-consumer-timeout': 1000 * 60 * 60 * 24,
914
- 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
915
- },
916
- };
917
- try {
918
- const channel = await this.assertChannelOld();
919
- debug('assertQueue->channel.addSetup', { queueName });
920
- await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
921
- debug('assertQueue->channel.assertQueue', { queueName });
922
- queue = await channel.assertQueue(queueName, localeOptions);
923
- }
924
- catch (e) {
925
- logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
926
- if (!this.options?.dontRetryAssert) {
927
- debug('retrying assertQueue', { queueName });
928
- const channel = await this.assertChannelOld({ force: true });
929
- await this.deleteQueueOld(queueName);
930
- debug('retrying assertQueue->channel.addSetup', { queueName });
931
- await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
932
- debug('retrying assertQueue->channel.assertQueue', { queueName });
933
- queue = await channel.assertQueue(queueName, localeOptions);
934
- }
935
- else {
936
- throw e;
937
- }
938
- }
939
- this.oldQueues[queueName] = queue;
940
- return queue;
941
- }
942
- async assertChannelOld({ force = false } = {}) {
943
- if (!this.oldPublishChannelSetupPromise) {
944
- this.oldPublishChannelSetupPromise = new Promise(async (resolve, reject) => {
945
- if (this.oldChannel && !force) {
946
- return resolve(this.oldChannel);
947
- }
948
- try {
949
- const channel = await this.getNewChannelOld({});
950
- channel.on('error', (err) => {
951
- logger_1.default.error('rabbit: channel error', { err });
952
- });
953
- this.oldChannel = channel;
954
- resolve(channel);
955
- }
956
- catch (e) {
957
- reject(e);
958
- }
959
- });
960
- }
961
- return this.oldPublishChannelSetupPromise;
962
- }
963
- async deleteQueueOld(queue) {
964
- RabbitMq.validateName('queue', queue);
965
- const channel = await this.assertChannelOld();
966
- logger_1.default.info('rabbit: deleting queue', { queue });
967
- const deleteQueueRes = await channel.deleteQueue(queue);
968
- debug('queue deleted', deleteQueueRes);
969
- return deleteQueueRes;
970
- }
971
- async assertExchangeOld(exchangeName, options) {
972
- const channel = await this.assertChannelOld();
973
- if (this.oldExchanges[exchangeName]) {
974
- delete this.oldAssertExchangePromises[exchangeName];
975
- return this.oldExchanges[exchangeName];
976
- }
977
- if (this.oldAssertExchangePromises[exchangeName]) {
978
- return this.oldAssertExchangePromises[exchangeName];
979
- }
980
- this.oldAssertExchangePromises[exchangeName] = (0, utils_1.assertExchangeFanout)(channel, exchangeName);
981
- this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
982
- return this.oldExchanges[exchangeName];
983
- }
984
626
  }
985
627
  exports.default = RabbitMq;
986
- var celery_1 = require("./lib/celery");
987
- Object.defineProperty(exports, "sendCeleryTaskViaHttp", { enumerable: true, get: function () { return celery_1.sendCeleryTaskViaHttp; } });
988
- //# sourceMappingURL=index.js.map