@autofleet/rabbit 3.3.0 → 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;
@@ -188,18 +172,6 @@ class RabbitMq {
188
172
  await this.gracefulShutdown('SIGINT');
189
173
  });
190
174
  }
191
- // TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
192
- this.oldEm = new events_1.EventEmitter();
193
- this.oldChannel = null;
194
- this.oldPublishChannelSetupPromise = null;
195
- this.oldConnection = null;
196
- this.oldCreatingConnection = false;
197
- this.oldExchanges = {};
198
- this.oldQueues = {};
199
- this.oldQueueSetupPromises = {};
200
- this.oldAssertExchangePromises = {};
201
- this.oldConsumers = [];
202
- this.oldConsumersTags = [];
203
175
  }
204
176
  async getConnection() {
205
177
  return new Promise(async (resolve, reject) => {
@@ -234,7 +206,7 @@ class RabbitMq {
234
206
  const password = process.env.RABBITMQ_PASSWORD || 'guest';
235
207
  const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
236
208
  debug('rabbit: creating connection', { host, userName, HEARTBEAT });
237
- return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
209
+ return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
238
210
  };
239
211
  const defaultUrls = findServers();
240
212
  const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
@@ -251,7 +223,7 @@ class RabbitMq {
251
223
  });
252
224
  this.connection.on('connectFailed', (err) => {
253
225
  this.consumersTags = [];
254
- 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 });
255
227
  if (!isResolved) {
256
228
  isResolved = true;
257
229
  reject(err);
@@ -337,12 +309,11 @@ class RabbitMq {
337
309
  this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
338
310
  return this.exchanges[exchangeName];
339
311
  }
340
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
341
312
  async getQueueLength(queue) {
342
313
  RabbitMq.validateName('queue', queue);
343
- const { oldChannel: channel } = this;
314
+ const { channel } = this;
344
315
  if (!channel) {
345
- throw new rabbitError_1.default('channel is not defined');
316
+ throw new Error('channel is not defined');
346
317
  }
347
318
  debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
348
319
  return channel?.checkQueue(queue);
@@ -355,29 +326,27 @@ class RabbitMq {
355
326
  debug('queue deleted', deleteQueueRes);
356
327
  return deleteQueueRes;
357
328
  }
358
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
359
329
  async bindQueue(queue, exchange) {
360
- const channel = await this.assertChannelOld();
330
+ const channel = await this.assertChannel();
361
331
  await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
362
332
  return channel.bindQueue(queue, exchange, '');
363
333
  }
364
334
  async setupQueue(queueName, options) {
365
335
  let queue;
336
+ const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
366
337
  const localeOptions = {
367
338
  ...options,
368
339
  durable: true,
369
340
  arguments: {
370
341
  ...options?.arguments,
371
342
  'x-consumer-timeout': 1000 * 60 * 60 * 24,
372
- 'x-queue-type': 'quorum',
343
+ 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
373
344
  },
374
345
  };
375
346
  try {
376
347
  const channel = await this.assertChannel();
377
348
  debug('assertQueue->channel.addSetup', { queueName });
378
- await channel.addSetup(async (setupChannel) => {
379
- await setupChannel.assertQueue(queueName, localeOptions);
380
- });
349
+ await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
381
350
  debug('assertQueue->channel.assertQueue', { queueName });
382
351
  queue = await channel.assertQueue(queueName, localeOptions);
383
352
  }
@@ -399,7 +368,6 @@ class RabbitMq {
399
368
  this.queues[queueName] = queue;
400
369
  return queue;
401
370
  }
402
- // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
403
371
  static shouldUseQuorum(queueName) {
404
372
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
405
373
  if (envQuorumQueuesWhitelist === '*') {
@@ -434,23 +402,9 @@ class RabbitMq {
434
402
  });
435
403
  }
436
404
  }
437
- // Used by the microservices to consume messages from the queue
438
405
  async consume(queue, callback, options) {
439
- // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
440
- if (options?.isQuorumQueue !== false) {
441
- await this.assertVHost();
442
- await this.consumeNew(queue, callback, options);
443
- }
444
- await this.consumeOld(queue, callback, options);
445
- }
446
- // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
447
- async consumeNew(queue, callback, options) {
448
406
  await this.consumeFromRabbit(queue, callback, options);
449
407
  }
450
- // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
451
- async consumeOld(queue, callback, options) {
452
- await this.consumeFromRabbitOld(queue, callback, options);
453
- }
454
408
  async lockRedisIfNeeded(msg, options) {
455
409
  const { properties: { headers } } = msg;
456
410
  const timestamp = headers?.creationTimestamp;
@@ -473,7 +427,7 @@ class RabbitMq {
473
427
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
474
428
  if (useConsumeWithLock) {
475
429
  if (!this.redisLock) {
476
- throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
430
+ throw new Error('Usage of consumeWithLock requires RedisInstance');
477
431
  }
478
432
  logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
479
433
  }
@@ -555,57 +509,35 @@ class RabbitMq {
555
509
  }
556
510
  });
557
511
  }
558
- // Used by the microservices to consume messages from the exchange
559
512
  async consumeFromExchange(queue, exchange, callback, options) {
560
513
  const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
561
514
  RabbitMq.validateName('exchange', exchange);
562
515
  RabbitMq.validateName('queue', queue);
563
516
  const { limit, deadMessageTtl } = optionsWithDefaults;
564
- // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
565
- if (options?.isQuorumQueue !== false) {
566
- await this.assertVHost();
567
- await this.saveConsumer(queue, callback, options);
568
- const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
569
- await channel.addSetup(async (c) => {
570
- const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
571
- await c.assertQueue(queue);
572
- this.exchanges[exchange] = assertExchange;
573
- await c.prefetch(limit, false);
574
- return Promise.all([
575
- c.bindQueue(queue, exchange, ''),
576
- this.consumeNew(queue, callback, options),
577
- ]);
578
- });
579
- }
580
- // TODO: [QUORUM-PHASE-3] Delete the old implementation
581
- await this.saveConsumerOld(queue, callback, options);
582
- const channelOld = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
583
- 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) => {
584
520
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
585
521
  await c.assertQueue(queue);
586
- this.oldExchanges[exchange] = assertExchange;
587
- await c.prefetch(limit, false);
522
+ this.exchanges[exchange] = assertExchange;
523
+ await c.prefetch(limit, true);
588
524
  return Promise.all([
589
525
  c.bindQueue(queue, exchange, ''),
590
- this.consumeOld(queue, callback, options),
526
+ this.consume(queue, callback, options),
591
527
  ]);
592
528
  });
593
529
  }
594
- // Used by the microservices to publish messages to the exchange
595
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
596
530
  async publish(exchange, content, customHeaders) {
597
531
  return (0, utils_1.wrapSetImmediate)(async () => {
598
532
  RabbitMq.validateName('exchange', exchange);
599
- const channel = await this.assertChannelOld();
600
- await this.assertExchangeOld(exchange);
533
+ const channel = await this.assertChannel();
534
+ await this.assertExchange(exchange);
601
535
  await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
602
536
  });
603
537
  }
604
- // Used by the microservices to send messages to the queue
605
- // TODO: [QUORUM-PHASE-2] Change the implementation to the new one
606
538
  async sendToQueue(queue, content, options, customHeaders) {
607
539
  try {
608
- await this.assertChannelOld();
540
+ await this.assertChannel();
609
541
  }
610
542
  catch (e) {
611
543
  logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
@@ -613,14 +545,14 @@ class RabbitMq {
613
545
  }
614
546
  try {
615
547
  RabbitMq.validateName('queue', queue);
616
- await this.assertQueueOld(queue, options);
548
+ await this.assertQueue(queue, options);
617
549
  }
618
550
  catch (e) {
619
551
  logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
620
552
  throw e;
621
553
  }
622
554
  try {
623
- 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));
624
556
  debug(`rabbit: sending to queue ${queue}`, { res });
625
557
  return res;
626
558
  }
@@ -630,38 +562,59 @@ class RabbitMq {
630
562
  throw e;
631
563
  }
632
564
  }
633
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
634
565
  async isConnected() {
635
- const connection = await this.getConnectionOld();
636
- const isConnected = connection.isConnected();
637
- if (!isConnected) {
638
- logger_1.default.error('rabbit: isConnected - false');
639
- return false;
640
- }
641
- const channel = await this.assertChannelOld();
642
566
  try {
643
- await Promise.all([
644
- channel.waitForConnect(),
645
- ...this.oldConsumers.map((c) => channel.checkQueue(c.queue)),
646
- ]);
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;
647
605
  }
648
606
  catch (e) {
649
- logger_1.default.error('rabbit: isConnected - false');
607
+ logger_1.default.error(`rabbit: isConnected - Exception occurred: ${e}`);
650
608
  return false;
651
609
  }
652
- logger_1.default.info('rabbit: isConnected - true');
653
- return true;
654
610
  }
655
611
  async gracefulShutdown(signal) {
656
- // TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
657
- const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
612
+ const tagsNumber = this.consumersTags.length;
658
613
  logger_1.default.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
659
614
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
660
- const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
661
615
  // Clean the array to avoid race
662
616
  this.consumersTags = [];
663
- this.oldConsumersTags = [];
664
- const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
617
+ const results = await Promise.allSettled(cancelTagPromises);
665
618
  const rejected = results.filter((p) => p.status === 'rejected');
666
619
  if (rejected.length > 0) {
667
620
  logger_1.default.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
@@ -670,301 +623,5 @@ class RabbitMq {
670
623
  logger_1.default.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
671
624
  }
672
625
  }
673
- async consumeFromRabbitOld(queue, callback, options) {
674
- const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
675
- RabbitMq.validateName('queue', queue);
676
- this.saveConsumerOld(queue, callback, options);
677
- const uniqueId = (0, node_crypto_1.randomUUID)();
678
- const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
679
- if (useConsumeWithLock) {
680
- if (!this.redisLock) {
681
- throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
682
- }
683
- logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
684
- }
685
- const channel = await this.getNewChannelOld({});
686
- return channel.addSetup(async (confirmChannel) => {
687
- const q = await this.assertQueueOld(queue, optionsWithDefaults);
688
- await confirmChannel.prefetch(limit, false);
689
- const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
690
- if (!msg) {
691
- return null;
692
- }
693
- const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
694
- const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
695
- const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
696
- const parsedMessage = RabbitMq.parseMsg(msg);
697
- const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
698
- const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
699
- // setting also outbreak trace as part of legacy code
700
- const outbreakTrace = zehut_1.outbreak.newTrace(zehut_1.traceTypes.RABBIT);
701
- // enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
702
- // and we don't want to fail the flow because of it
703
- if (userId && enableRabbitTrace) {
704
- try {
705
- await Promise.all([
706
- (0, zehut_1.createOrSetRabbitTrace)(trace, userId),
707
- (0, zehut_1.createOrSetRabbitTrace)(outbreakTrace, userId),
708
- ]);
709
- }
710
- catch (e) {
711
- logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
712
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
713
- }
714
- }
715
- if (traceId) {
716
- trace?.context?.set(consts_1.TRACING_HEADER, traceId);
717
- outbreakTrace?.context.set(consts_1.TRACING_HEADER, traceId);
718
- }
719
- if (auditContext) {
720
- await auditContext(queue, {
721
- userId,
722
- automationId,
723
- });
724
- }
725
- const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
726
- if (!shouldConsume) {
727
- await this.unlockRedisIfNeeded(releaseLock);
728
- return this.ack(confirmChannel, msg)(msg);
729
- }
730
- let messageAcked = false;
731
- // setting the localAck function to be used in the callback
732
- const localAck = async () => {
733
- if (messageAcked) {
734
- return;
735
- }
736
- messageAcked = true;
737
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
738
- };
739
- const localNack = async (_, nackOptions = {}) => {
740
- if (messageAcked) {
741
- return;
742
- }
743
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
744
- messageAcked = true;
745
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
746
- };
747
- try {
748
- await callback(parsedMessage, localAck, localNack);
749
- }
750
- catch (e) {
751
- await localNack(msg);
752
- }
753
- }, types_1.CONSUMER_DEFAULT_OPTIONS);
754
- if (!consumerTag) {
755
- logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
756
- }
757
- else {
758
- logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
759
- this.oldConsumersTags.push([confirmChannel, consumerTag]);
760
- }
761
- });
762
- }
763
- // TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
764
- async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
765
- let connection;
766
- try {
767
- connection = await this.getConnectionOld();
768
- }
769
- catch (e) {
770
- logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
771
- throw e;
772
- }
773
- const channel = connection.createChannel({ ...options });
774
- (0, events_1.once)(channel, 'close').then((args) => {
775
- logger_1.default.error(`rabbit: channel ${name} closed`);
776
- onClose?.(args);
777
- });
778
- try {
779
- await (0, events_1.once)(channel, 'connect');
780
- debug(`rabbit: channel ${name} CONNECTED`);
781
- return channel;
782
- }
783
- catch (err) {
784
- logger_1.default.error(`rabbit: channel error ${name} error`, { err });
785
- throw err;
786
- }
787
- }
788
- async getConnectionOld() {
789
- return new Promise(async (resolve, reject) => {
790
- if (this.oldBlockReconnect) {
791
- debug('rabbit: block reconnect');
792
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
793
- // @ts-ignore
794
- return resolve();
795
- }
796
- if (this.oldConnection !== null) {
797
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
798
- debug('rabbit: connection - is connected');
799
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
800
- // @ts-ignore
801
- return resolve(this.oldConnection);
802
- }
803
- debug('rabbit: connection - reconnecting');
804
- }
805
- if (this.oldCreatingConnection) {
806
- debug('rabbit: creating connection emi');
807
- this.oldEm.once(consts_1.CONNECTION_CREATED_CONST, resolve);
808
- this.oldEm.once(consts_1.CONNECTION_FAILED_CONST, reject);
809
- return;
810
- }
811
- this.oldCreatingConnection = true;
812
- let isResolved = false;
813
- // It is import to use it as a function and not as a variable
814
- // because of k8s changes the env variables
815
- // and we want to use the new values
816
- const findServers = () => {
817
- const userName = process.env.RABBITMQ_USERNAME || 'guest';
818
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
819
- const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
820
- debug('rabbit: creating connection', { host, userName, HEARTBEAT });
821
- return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
822
- };
823
- const defaultUrls = findServers();
824
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
825
- findServers,
826
- });
827
- this.oldConnection = connection;
828
- this.oldConnection.on('error', (err) => {
829
- logger_1.default.error('rabbit: connection error', { err });
830
- if (!isResolved) {
831
- isResolved = true;
832
- reject(err);
833
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
834
- }
835
- });
836
- this.oldConnection.on('connectFailed', (err) => {
837
- this.oldConsumersTags = [];
838
- logger_1.default.error('rabbit: connection connectFailed', { err });
839
- if (!isResolved) {
840
- isResolved = true;
841
- reject(err);
842
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
843
- }
844
- });
845
- this.oldConnection.on('disconnect', ({ err }) => {
846
- this.oldConsumersTags = [];
847
- debug('rabbit: connection closed');
848
- if (this.options?.disableReconnect) {
849
- logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
850
- this.oldBlockReconnect = true;
851
- }
852
- else {
853
- logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
854
- }
855
- });
856
- this.oldConnection.once('connect', async () => {
857
- debug('rabbit: connection established');
858
- this.oldCreatingConnection = false;
859
- this.oldEm.emit(consts_1.CONNECTION_CREATED_CONST, connection);
860
- isResolved = true;
861
- resolve(connection);
862
- });
863
- });
864
- }
865
- saveConsumerOld(queue, callback, options) {
866
- const isConsumerExist = this.oldConsumers.some((consumer) => consumer.queue === queue);
867
- if (!isConsumerExist) {
868
- logger_1.default.info(`rabbit: consumer: ${queue} saved in consumer array`);
869
- this.oldConsumers.push({
870
- queue,
871
- callback,
872
- options,
873
- });
874
- }
875
- }
876
- async assertQueueOld(queueName, options) {
877
- RabbitMq.validateName('queue', queueName);
878
- if (this.oldQueues[queueName]) {
879
- delete this.oldQueueSetupPromises[queueName];
880
- return this.oldQueues[queueName];
881
- }
882
- if (this.oldQueueSetupPromises[queueName]) {
883
- return this.oldQueueSetupPromises[queueName];
884
- }
885
- this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
886
- return this.oldQueueSetupPromises[queueName];
887
- }
888
- async setupQueueOld(queueName, options) {
889
- let queue;
890
- const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
891
- const localeOptions = {
892
- ...options,
893
- durable: true,
894
- arguments: {
895
- ...options?.arguments,
896
- 'x-consumer-timeout': 1000 * 60 * 60 * 24,
897
- 'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
898
- },
899
- };
900
- try {
901
- const channel = await this.assertChannelOld();
902
- debug('assertQueue->channel.addSetup', { queueName });
903
- await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
904
- debug('assertQueue->channel.assertQueue', { queueName });
905
- queue = await channel.assertQueue(queueName, localeOptions);
906
- }
907
- catch (e) {
908
- logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
909
- if (!this.options?.dontRetryAssert) {
910
- debug('retrying assertQueue', { queueName });
911
- const channel = await this.assertChannelOld({ force: true });
912
- await this.deleteQueueOld(queueName);
913
- debug('retrying assertQueue->channel.addSetup', { queueName });
914
- await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
915
- debug('retrying assertQueue->channel.assertQueue', { queueName });
916
- queue = await channel.assertQueue(queueName, localeOptions);
917
- }
918
- else {
919
- throw e;
920
- }
921
- }
922
- this.oldQueues[queueName] = queue;
923
- return queue;
924
- }
925
- async assertChannelOld({ force = false } = {}) {
926
- if (!this.oldPublishChannelSetupPromise) {
927
- this.oldPublishChannelSetupPromise = new Promise(async (resolve, reject) => {
928
- if (this.oldChannel && !force) {
929
- return resolve(this.oldChannel);
930
- }
931
- try {
932
- const channel = await this.getNewChannelOld({});
933
- channel.on('error', (err) => {
934
- logger_1.default.error('rabbit: channel error', { err });
935
- });
936
- this.oldChannel = channel;
937
- resolve(channel);
938
- }
939
- catch (e) {
940
- reject(e);
941
- }
942
- });
943
- }
944
- return this.oldPublishChannelSetupPromise;
945
- }
946
- async deleteQueueOld(queue) {
947
- RabbitMq.validateName('queue', queue);
948
- const channel = await this.assertChannelOld();
949
- logger_1.default.info('rabbit: deleting queue', { queue });
950
- const deleteQueueRes = await channel.deleteQueue(queue);
951
- debug('queue deleted', deleteQueueRes);
952
- return deleteQueueRes;
953
- }
954
- async assertExchangeOld(exchangeName, options) {
955
- const channel = await this.assertChannelOld();
956
- if (this.oldExchanges[exchangeName]) {
957
- delete this.oldAssertExchangePromises[exchangeName];
958
- return this.oldExchanges[exchangeName];
959
- }
960
- if (this.oldAssertExchangePromises[exchangeName]) {
961
- return this.oldAssertExchangePromises[exchangeName];
962
- }
963
- this.oldAssertExchangePromises[exchangeName] = (0, utils_1.assertExchangeFanout)(channel, exchangeName);
964
- this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
965
- return this.oldExchanges[exchangeName];
966
- }
967
626
  }
968
627
  exports.default = RabbitMq;
969
- var celery_1 = require("./lib/celery");
970
- Object.defineProperty(exports, "sendCeleryTaskViaHttp", { enumerable: true, get: function () { return celery_1.sendCeleryTaskViaHttp; } });