@autofleet/rabbit 4.1.0-beta.0 → 4.1.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 (60) hide show
  1. package/dist/index.d.ts +81 -77
  2. package/dist/index.js +581 -472
  3. package/dist/index.js.map +1 -0
  4. package/dist/lib/celery.js +2 -2
  5. package/dist/lib/celery.js.map +1 -0
  6. package/dist/lib/consts.d.ts +12 -4
  7. package/dist/lib/consts.js +12 -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.d.ts +2 -1
  12. package/dist/lib/redis.js +3 -8
  13. package/dist/lib/redis.js.map +1 -0
  14. package/dist/lib/types.d.ts +18 -5
  15. package/dist/lib/types.js +1 -0
  16. package/dist/lib/types.js.map +1 -0
  17. package/dist/lib/utils.d.ts +12 -3
  18. package/dist/lib/utils.js +23 -13
  19. package/dist/lib/utils.js.map +1 -0
  20. package/dist/logger.js +1 -0
  21. package/dist/logger.js.map +1 -0
  22. package/dist/{mock.d.ts → mock/index.d.ts} +1 -1
  23. package/dist/{mock.js → mock/index.js} +2 -1
  24. package/dist/mock/index.js.map +1 -0
  25. package/dist/mock/vitest.d.ts +13 -0
  26. package/dist/mock/vitest.js +18 -0
  27. package/dist/mock/vitest.js.map +1 -0
  28. package/package.json +24 -19
  29. package/src/index.ts +702 -591
  30. package/src/lib/consts.ts +17 -4
  31. package/src/lib/redis.ts +2 -7
  32. package/src/lib/types.ts +22 -7
  33. package/src/lib/utils.ts +35 -12
  34. package/src/{mock.ts → mock/index.ts} +2 -2
  35. package/src/mock/vitest.ts +24 -0
  36. package/src/redis-lock.d.ts +5 -3
  37. package/tsconfig.build.json +5 -0
  38. package/tsconfig.json +2 -2
  39. package/vitest.config.ts +17 -0
  40. package/coverage/clover.xml +0 -669
  41. package/coverage/coverage-final.json +0 -9
  42. package/coverage/lcov-report/base.css +0 -224
  43. package/coverage/lcov-report/block-navigation.js +0 -87
  44. package/coverage/lcov-report/favicon.png +0 -0
  45. package/coverage/lcov-report/index.html +0 -131
  46. package/coverage/lcov-report/prettify.css +0 -1
  47. package/coverage/lcov-report/prettify.js +0 -2
  48. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  49. package/coverage/lcov-report/sorter.js +0 -196
  50. package/coverage/lcov-report/src/index.html +0 -131
  51. package/coverage/lcov-report/src/index.ts.html +0 -3826
  52. package/coverage/lcov-report/src/lib/celery.ts.html +0 -352
  53. package/coverage/lcov-report/src/lib/consts.ts.html +0 -142
  54. package/coverage/lcov-report/src/lib/index.html +0 -191
  55. package/coverage/lcov-report/src/lib/rabbitError.ts.html +0 -103
  56. package/coverage/lcov-report/src/lib/redis.ts.html +0 -133
  57. package/coverage/lcov-report/src/lib/types.ts.html +0 -268
  58. package/coverage/lcov-report/src/lib/utils.ts.html +0 -142
  59. package/coverage/lcov-report/src/logger.ts.html +0 -100
  60. package/coverage/lcov.info +0 -1076
package/dist/index.js CHANGED
@@ -1,36 +1,47 @@
1
1
  "use strict";
2
- /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars */
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
3
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
15
  };
16
+ var _RabbitMq_logger;
6
17
  Object.defineProperty(exports, "__esModule", { value: true });
7
18
  exports.sendCeleryTaskViaHttp = void 0;
8
- const events_1 = require("events");
9
- const util_1 = require("util");
19
+ const node_process_1 = require("node:process");
20
+ const promises_1 = require("node:timers/promises");
21
+ const node_events_1 = require("node:events");
10
22
  const moment_1 = __importDefault(require("moment"));
11
23
  const redis_lock_1 = __importDefault(require("redis-lock"));
12
24
  const amqp_connection_manager_1 = require("amqp-connection-manager");
25
+ const exponential_backoff_1 = require("exponential-backoff");
13
26
  const zehut_1 = require("@autofleet/zehut");
14
27
  const node_crypto_1 = require("node:crypto");
15
- const axios_1 = __importDefault(require("axios"));
16
28
  const logger_1 = __importDefault(require("./logger"));
17
29
  const rabbitError_1 = __importDefault(require("./lib/rabbitError"));
18
30
  const redis_1 = __importDefault(require("./lib/redis"));
19
31
  const utils_1 = require("./lib/utils");
20
32
  const consts_1 = require("./lib/consts");
21
33
  const types_1 = require("./lib/types");
22
- // const debug = nodeDebug('af-rabbitmq')
23
- const debug = logger_1.default.debug.bind(logger_1.default);
24
34
  const PUBLISH_TIMEOUT = 1000 * 10;
35
+ // TODO: [QUORUM-PHASE-3] Delete these env vars
36
+ const { DISABLE_QUORUM_QUEUES_CONSUME, DISABLE_QUORUM_QUEUES_PUBLISH, } = node_process_1.env;
25
37
  const HEARTBEAT = '60';
26
38
  class RabbitMq {
27
39
  static parseMsg(msg) {
28
- let { content } = msg;
29
- content = content.toString();
40
+ let content = msg.content.toString();
30
41
  try {
31
42
  content = JSON.parse(content);
32
43
  }
33
- catch (e) { }
44
+ catch { /* ignore error */ }
34
45
  return {
35
46
  ...msg,
36
47
  content,
@@ -42,10 +53,8 @@ class RabbitMq {
42
53
  }
43
54
  }
44
55
  static getPublishOptions(customHeaders = {}) {
45
- const trace = (0, zehut_1.getCurrentPayload)();
46
- const user = trace?.context?.get(consts_1.USER_OBJECT);
47
- const traceId = trace?.context?.get(consts_1.TRACING_HEADER);
48
- const outbreakTrace = zehut_1.outbreak.getCurrentContext();
56
+ const user = (0, zehut_1.getUser)();
57
+ const traceId = (0, zehut_1.getCurrentPayload)()?.context?.get(consts_1.TRACING_HEADER) || zehut_1.outbreak.getCurrentContext()?.context?.get(consts_1.TRACING_HEADER);
49
58
  return {
50
59
  timestamp: (0, moment_1.default)().unix(),
51
60
  timeout: PUBLISH_TIMEOUT,
@@ -53,65 +62,118 @@ class RabbitMq {
53
62
  creationTimestamp: (0, moment_1.default)().valueOf(),
54
63
  ...customHeaders,
55
64
  [consts_1.USER_TRACING_HEADER]: user?.id,
56
- [consts_1.TRACING_HEADER]: traceId || outbreakTrace?.context?.get(consts_1.TRACING_HEADER),
65
+ [consts_1.TRACING_HEADER]: traceId,
57
66
  },
58
67
  };
59
68
  }
60
69
  constructor(options = {}, redisConfig) {
70
+ this.options = options;
71
+ this.redisConfig = redisConfig;
61
72
  this.DISCONNECT_MSG = 'rabbit: connection disconnect';
62
73
  this.RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
63
- this.consumers = [];
64
- this.isVHostExist = false;
65
- this.oldConsumers = [];
74
+ this.publishChannel = null;
75
+ this.publishChannelSetupPromise = null;
76
+ this.publishConnection = {
77
+ amqpConnection: null,
78
+ creatingConnection: false,
79
+ connectionCreatedEventName: 'publishConnectionCreated',
80
+ connectionFailedEventName: 'publishConnectionFailed',
81
+ blockReconnect: false,
82
+ };
83
+ this.consumeConnection = {
84
+ amqpConnection: null,
85
+ creatingConnection: false,
86
+ connectionCreatedEventName: 'consumeConnectionCreated',
87
+ connectionFailedEventName: 'consumeConnectionFailed',
88
+ blockReconnect: false,
89
+ };
90
+ this.em = new node_events_1.EventEmitter();
91
+ this.exchanges = {};
92
+ this.queues = {};
93
+ this.queueSetupPromises = {};
94
+ this.assertExchangePromises = {};
95
+ /** Array of consumers tags used for canceling consumption */
96
+ this.consumersTags = new Map();
97
+ this.consumersToRegister = [];
98
+ this.doesVHostExist = false;
99
+ this.vhost = 'quorum-vhost';
100
+ this.gracefulShutdownStarted = false;
101
+ // TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
102
+ this.oldPublishChannel = null;
103
+ this.oldPublishChannelSetupPromise = null;
104
+ this.oldPublishConnection = {
105
+ amqpConnection: null,
106
+ creatingConnection: false,
107
+ connectionCreatedEventName: 'oldPublishConnectionCreated',
108
+ connectionFailedEventName: 'oldPublishConnectionFailed',
109
+ blockReconnect: false,
110
+ };
111
+ this.oldConsumeConnection = {
112
+ amqpConnection: null,
113
+ creatingConnection: false,
114
+ connectionCreatedEventName: 'oldConsumeConnectionCreated',
115
+ connectionFailedEventName: 'oldConsumeConnectionFailed',
116
+ blockReconnect: false,
117
+ };
118
+ this.oldEm = new node_events_1.EventEmitter();
119
+ this.oldExchanges = {};
120
+ this.oldQueues = {};
121
+ this.oldQueueSetupPromises = {};
122
+ this.oldAssertExchangePromises = {};
123
+ this.oldConsumersTags = new Map();
124
+ this.oldConsumersToRegister = [];
125
+ _RabbitMq_logger.set(this, void 0);
66
126
  this.assertVHost = async () => {
67
- if (this.isVHostExist) {
127
+ if (this.doesVHostExist) {
68
128
  return;
69
129
  }
70
- if (!this.options?.vhost) {
71
- throw new Error('vhost is not defined');
72
- }
73
- const { vhost } = this.options;
74
- const auth = {
75
- auth: {
76
- username: process.env.RABBITMQ_USERNAME || 'guest',
77
- password: process.env.RABBITMQ_PASSWORD || 'guest',
78
- },
130
+ const username = process.env.RABBITMQ_USERNAME || 'guest';
131
+ const password = process.env.RABBITMQ_PASSWORD || 'guest';
132
+ const credentials = Buffer.from(`${username}:${password}`).toString('base64');
133
+ const headers = {
134
+ Authorization: `Basic ${credentials}`,
135
+ 'Content-Type': 'application/json',
79
136
  };
80
- const rabbitHost = `http://${(this.options.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
137
+ const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
138
+ const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
81
139
  try {
82
- const response = await axios_1.default.get(`${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`, auth);
83
- if (response.status !== 200) {
84
- throw new Error('Failed to check vhost');
140
+ const response = await fetch(url, {
141
+ method: 'GET',
142
+ headers,
143
+ });
144
+ if (response.status === 200) {
145
+ this.doesVHostExist = true;
146
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info('Vhost exists', { vhost: this.vhost });
147
+ return;
85
148
  }
86
- this.isVHostExist = true;
87
- logger_1.default.info('Vhost exists', { vhost });
149
+ if (response.status !== 404) {
150
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('Failed to check vhost', { response });
151
+ throw new rabbitError_1.default('Failed to check vhost');
152
+ }
153
+ const createResponse = await fetch(url, {
154
+ method: 'PUT',
155
+ headers,
156
+ body: JSON.stringify({ default_queue_type: 'quorum' }),
157
+ });
158
+ if (!createResponse.ok) {
159
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('Failed to create vhost', { response: createResponse });
160
+ throw new rabbitError_1.default('Failed to create vhost');
161
+ }
162
+ this.doesVHostExist = true;
163
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info('Vhost created', { vhost: this.vhost });
88
164
  }
89
165
  catch (error) {
90
- // If the vhost does not exist, create it
91
- if (error instanceof axios_1.default.AxiosError && error.response?.status === 404) {
92
- try {
93
- await axios_1.default.put(`${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`, {
94
- default_queue_type: 'quorum',
95
- }, auth);
96
- this.isVHostExist = true;
97
- logger_1.default.info('Vhost created', { vhost: this.options?.vhost });
98
- return;
99
- }
100
- catch (createError) {
101
- logger_1.default.error('Failed to create vhost', { error: createError });
102
- throw createError;
103
- }
104
- }
105
- logger_1.default.error('Failed to check vhost', { error });
166
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('Failed to check or create vhost', { error });
106
167
  throw error;
107
168
  }
108
169
  };
109
170
  this.shouldConsumeMessageByTimestamp = async (msg) => {
110
171
  if (msg) {
111
- const { properties: { headers } } = msg;
172
+ const { headers } = msg.properties;
112
173
  const timestamp = headers?.creationTimestamp;
113
174
  if (timestamp && headers?.redisTimestampValidationKey && this.redisClient) {
114
- const lastMessageTimestamp = await this.redisClient.getAsync(headers.redisTimestampValidationKey);
175
+ const key = this.getRedisKey(headers.redisTimestampValidationKey);
176
+ const lastMessageTimestamp = await this.redisClient.get(key);
115
177
  return !lastMessageTimestamp || (parseInt(lastMessageTimestamp, 10) <= parseInt(timestamp, 10));
116
178
  }
117
179
  return true;
@@ -120,68 +182,55 @@ class RabbitMq {
120
182
  };
121
183
  this.ack = (channel, msg, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg) => {
122
184
  if (msg) {
123
- debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
185
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
124
186
  await channel.ack(msg);
125
- const { properties: { headers } } = msg;
187
+ const { headers } = msg.properties;
126
188
  const timestamp = headers?.creationTimestamp;
127
189
  if (shouldUpdateRedisTimestamp && timestamp && headers?.redisTimestampValidationKey && this.redisClient) {
128
190
  const parsedTimestamp = parseInt(timestamp, 10);
129
- await this.redisClient.setAsync(headers.redisTimestampValidationKey, parsedTimestamp, 'EX', 3600);
191
+ const key = this.getRedisKey(headers.redisTimestampValidationKey);
192
+ await this.redisClient.set(key, parsedTimestamp, { EX: 3600 });
130
193
  await this.unlockRedisIfNeeded(releaseLock);
131
194
  }
132
195
  }
133
196
  };
134
197
  this.nack = (channel, queue, options, deadQueueOptions, msg, releaseLock) => async (userMsg, { skipRetry = false, } = {}) => {
135
198
  await this.unlockRedisIfNeeded(releaseLock);
136
- if (channel && msg) {
137
- if (!skipRetry
138
- && (!msg.properties.headers[consts_1.RETRY_HEADER]
139
- || parseInt(msg.properties.headers[consts_1.RETRY_HEADER], 10) < options.retries)) {
140
- await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
141
- ...msg.properties.headers,
142
- [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
143
- ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
144
- : 1,
145
- });
146
- }
147
- else {
148
- const deadQueue = `${queue}-dead`;
149
- await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
150
- ...msg.properties.headers,
151
- [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
152
- ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
153
- : 1,
154
- });
155
- }
156
- debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
157
- await channel.ack(msg);
199
+ if (!channel || !msg) {
200
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('no channel or msg', { msg });
201
+ return;
158
202
  }
159
- else {
160
- logger_1.default.error('no channel or msg', {
161
- msg,
162
- });
203
+ const currentRetryHeader = Number.parseInt(msg.properties.headers?.[consts_1.RETRY_HEADER] || '0', 10) || 0;
204
+ const sendToDeadQueue = skipRetry || currentRetryHeader >= options.retries;
205
+ await this.sendToQueue(`${queue}${sendToDeadQueue ? '-dead' : ''}`, RabbitMq.parseMsg(msg).content, sendToDeadQueue ? deadQueueOptions : options, {
206
+ ...msg.properties.headers,
207
+ [consts_1.RETRY_HEADER]: currentRetryHeader + 1,
208
+ });
209
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
210
+ await channel.ack(msg);
211
+ };
212
+ this.maskURL = (url) => {
213
+ try {
214
+ const urlObj = new URL(url);
215
+ urlObj.username = '***';
216
+ urlObj.password = '***';
217
+ return urlObj.toString();
218
+ }
219
+ catch {
220
+ return url;
163
221
  }
164
222
  };
165
- this.em = new events_1.EventEmitter();
166
- this.channel = null;
167
- this.publishChannelSetupPromise = null;
168
- this.connection = null;
169
- this.creatingConnection = false;
170
- this.exchanges = {};
171
- this.queues = {};
172
- this.queueSetupPromises = {};
173
- this.assertExchangePromises = {};
174
- this.consumers = [];
175
- this.options = options;
176
- if (!options?.vhost) {
177
- this.options.vhost = process.env.VHOST_NAME || 'quorum-vhost';
178
- }
179
- this.redisClient = redisConfig && (0, redis_1.default)(redisConfig);
180
- if (this.redisClient) {
181
- this.redisLock = (0, util_1.promisify)((0, redis_lock_1.default)(this.redisClient));
223
+ __classPrivateFieldSet(this, _RabbitMq_logger, options?.logger || logger_1.default, "f");
224
+ if (redisConfig) {
225
+ this.redisClient = (0, redis_1.default)(redisConfig).on('error', (err) => {
226
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: Redis error', { err, redisConfig });
227
+ });
228
+ this.redisClient.connect().catch((err) => {
229
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: Failed to connect to Redis', { err, redisConfig });
230
+ });
231
+ this.redisLock = (0, redis_lock_1.default)(this.redisClient);
182
232
  }
183
- this.consumersTags = [];
184
- logger_1.default.info(`rabbit: [gracefully-shutdown] adding gracefully shutdown for process.pid ${process.pid}`);
233
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: [gracefully-shutdown] adding gracefully shutdown for process.pid ${process.pid}`);
185
234
  if (!this.options?.dontGracefulShutdown) {
186
235
  process.on('SIGTERM', async () => {
187
236
  await this.gracefulShutdown('SIGTERM');
@@ -190,144 +239,139 @@ class RabbitMq {
190
239
  await this.gracefulShutdown('SIGINT');
191
240
  });
192
241
  }
193
- // TODO: DELETE OLD PROPERTIES
194
- this.oldEm = new events_1.EventEmitter();
195
- this.oldChannel = null;
196
- this.oldPublishChannelSetupPromise = null;
197
- this.oldConnection = null;
198
- this.oldCreatingConnection = false;
199
- this.oldExchanges = {};
200
- this.oldQueues = {};
201
- this.oldQueueSetupPromises = {};
202
- this.oldAssertExchangePromises = {};
203
- this.oldConsumers = [];
204
- this.oldConsumersTags = [];
205
242
  }
206
- async getConnection() {
207
- return new Promise(async (resolve, reject) => {
208
- if (this.blockReconnect) {
209
- debug('rabbit: block reconnect');
210
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
211
- // @ts-ignore
212
- return resolve();
213
- }
214
- if (this.connection !== null) {
215
- if (this.options?.disableReconnect || this.connection?.isConnected()) {
216
- debug('rabbit: connection - is connected');
217
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
218
- // @ts-ignore
219
- return resolve(this.connection);
220
- }
221
- debug('rabbit: connection - reconnecting');
243
+ getRedisKey(key) {
244
+ return `${this.redisConfig?.prefix || ''}${key}`;
245
+ }
246
+ async getConnection(connection) {
247
+ const { amqpConnection: connectionLocal, creatingConnection, connectionCreatedEventName, connectionFailedEventName, blockReconnect, } = connection;
248
+ if (blockReconnect) {
249
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: block reconnect');
250
+ // @ts-expect-error we are returning undefined while the function clearly expects a connection.
251
+ return undefined;
252
+ }
253
+ if (connectionLocal !== null) {
254
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
255
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection - is connected');
256
+ return connectionLocal;
222
257
  }
223
- if (this.creatingConnection) {
224
- debug('rabbit: creating connection emi');
225
- this.em.once(consts_1.CONNECTION_CREATED_CONST, resolve);
226
- this.em.once(consts_1.CONNECTION_FAILED_CONST, reject);
227
- return;
258
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection - reconnecting');
259
+ }
260
+ if (creatingConnection) {
261
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: creating connection emi');
262
+ const [event, value] = await Promise.race([connectionCreatedEventName, connectionFailedEventName].map((e) => (0, node_events_1.once)(this.em, e).then(([result]) => [e, result])));
263
+ if (event === connectionCreatedEventName) {
264
+ return value;
228
265
  }
229
- this.creatingConnection = true;
230
- let isResolved = false;
231
- // It is import to use it as a function and not as a variable
232
- // because of k8s changes the env variables
233
- // and we want to use the new values
234
- const findServers = () => {
235
- const userName = process.env.RABBITMQ_USERNAME || 'guest';
236
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
237
- const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
238
- debug('rabbit: creating connection', { host, userName, HEARTBEAT });
239
- return [`amqp://${userName}:${password}@${host}/${this.options?.vhost}?heartbeat=${HEARTBEAT}`];
240
- };
241
- const defaultUrls = findServers();
242
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
243
- findServers,
244
- });
245
- this.connection = connection;
246
- this.connection.on('error', (err) => {
247
- logger_1.default.error('rabbit: connection error', { err });
248
- if (!isResolved) {
249
- isResolved = true;
250
- reject(err);
251
- this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
252
- }
253
- });
254
- this.connection.on('connectFailed', (err) => {
255
- this.consumersTags = [];
256
- logger_1.default.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.options?.vhost });
257
- if (!isResolved) {
258
- isResolved = true;
259
- reject(err);
260
- this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
261
- }
262
- });
263
- this.connection.on('disconnect', ({ err }) => {
264
- // this.channel = null;
265
- this.consumersTags = [];
266
- debug('rabbit: connection closed');
267
- if (this.options?.disableReconnect) {
268
- logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
269
- this.blockReconnect = true;
270
- }
271
- else {
272
- logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
273
- }
274
- });
275
- this.connection.once('connect', async () => {
276
- debug('rabbit: connection established');
277
- this.creatingConnection = false;
278
- this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
266
+ throw value;
267
+ }
268
+ connection.creatingConnection = true;
269
+ let isResolved = false;
270
+ // It is import to use it as a function and not as a variable
271
+ // because of k8s changes the env variables
272
+ // and we want to use the new values
273
+ const findServers = () => {
274
+ const userName = process.env.RABBITMQ_USERNAME || 'guest';
275
+ const password = process.env.RABBITMQ_PASSWORD || 'guest';
276
+ const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
277
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: creating connection', { host, userName, HEARTBEAT });
278
+ return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
279
+ };
280
+ const defaultUrls = findServers();
281
+ const newConnection = (0, amqp_connection_manager_1.connect)(defaultUrls, { findServers });
282
+ connection.amqpConnection = newConnection;
283
+ const { promise, reject, resolve } = (0, utils_1.createDeferredPromise)();
284
+ newConnection.on('error', (err) => {
285
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: connection error', { err });
286
+ if (!isResolved) {
279
287
  isResolved = true;
280
- resolve(connection);
281
- });
288
+ reject(err);
289
+ this.em.emit(connectionFailedEventName, err);
290
+ }
291
+ });
292
+ newConnection.on('connectFailed', (err) => {
293
+ this.consumersTags.clear();
294
+ if (typeof err.url === 'string') {
295
+ err.url = this.maskURL(err.url);
296
+ }
297
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
298
+ if (!isResolved) {
299
+ isResolved = true;
300
+ reject(err);
301
+ this.em.emit(connectionFailedEventName, err);
302
+ }
303
+ });
304
+ newConnection.on('disconnect', ({ err }) => {
305
+ this.consumersTags.clear();
306
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection closed');
307
+ if (this.options?.disableReconnect) {
308
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
309
+ connection.blockReconnect = true;
310
+ }
311
+ else {
312
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
313
+ }
314
+ });
315
+ newConnection.once('connect', async () => {
316
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection established');
317
+ connection.creatingConnection = false;
318
+ this.em.emit(connectionCreatedEventName, newConnection);
319
+ isResolved = true;
320
+ resolve(newConnection);
282
321
  });
322
+ return promise;
283
323
  }
284
- async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
285
- let connection;
324
+ async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connection, }) {
325
+ let localConnection;
286
326
  try {
287
- connection = await this.getConnection();
327
+ localConnection = await this.getConnection(connection);
288
328
  }
289
329
  catch (e) {
290
- logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
330
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: error on get connection for new channel ${name} `, { e });
291
331
  throw e;
292
332
  }
293
- const channel = connection.createChannel({ ...options });
294
- (0, events_1.once)(channel, 'close').then((args) => {
295
- logger_1.default.error(`rabbit: channel ${name} closed`);
333
+ const channel = localConnection?.createChannel({ ...options });
334
+ (0, node_events_1.once)(channel, 'close').then((args) => {
335
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: channel ${name} closed`);
296
336
  onClose?.(args);
297
337
  });
298
338
  try {
299
- await (0, events_1.once)(channel, 'connect');
300
- debug(`rabbit: channel ${name} CONNECTED`);
339
+ await (0, node_events_1.once)(channel, 'connect');
340
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug(`rabbit: channel ${name} CONNECTED`);
301
341
  return channel;
302
342
  }
303
343
  catch (err) {
304
- logger_1.default.error(`rabbit: channel error ${name} error`, { err });
344
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: channel error ${name} error`, { err });
305
345
  throw err;
306
346
  }
307
347
  }
308
- async assertChannel({ force = false } = {}) {
309
- if (!this.publishChannelSetupPromise) {
310
- this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
311
- if (this.channel && !force) {
312
- return resolve(this.channel);
313
- }
314
- try {
315
- const channel = await this.getNewChannel({});
316
- channel.on('error', (err) => {
317
- logger_1.default.error('rabbit: channel error', { err });
318
- });
319
- this.channel = channel;
320
- resolve(channel);
321
- }
322
- catch (e) {
323
- reject(e);
324
- }
348
+ async assertChannel({ force = false, connection }) {
349
+ if (this.publishChannelSetupPromise) {
350
+ return this.publishChannelSetupPromise;
351
+ }
352
+ const { promise, resolve, reject } = (0, utils_1.createDeferredPromise)();
353
+ this.publishChannelSetupPromise = promise;
354
+ if (this.publishChannel && !force) {
355
+ resolve(this.publishChannel);
356
+ return promise;
357
+ }
358
+ try {
359
+ const channel = await this.getNewChannel({ connection });
360
+ channel.on('error', (err) => {
361
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: channel error', { err });
325
362
  });
363
+ if (this.publishConnection === connection) {
364
+ this.publishChannel = channel;
365
+ }
366
+ resolve(channel);
367
+ }
368
+ catch (e) {
369
+ reject(e);
326
370
  }
327
- return this.publishChannelSetupPromise;
371
+ return promise;
328
372
  }
329
- async assertExchange(exchangeName, options) {
330
- const channel = await this.assertChannel();
373
+ async assertExchange(exchangeName, connection) {
374
+ const channel = await this.assertChannel({ connection });
331
375
  if (this.exchanges[exchangeName]) {
332
376
  delete this.assertExchangePromises[exchangeName];
333
377
  return this.exchanges[exchangeName];
@@ -341,28 +385,29 @@ class RabbitMq {
341
385
  }
342
386
  async getQueueLength(queue) {
343
387
  RabbitMq.validateName('queue', queue);
344
- const { channel } = this;
388
+ const { publishChannel: channel } = this;
345
389
  if (!channel) {
346
- throw new Error('channel is not defined');
390
+ throw new rabbitError_1.default('channel is not defined');
347
391
  }
348
- debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
392
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: getting queue length', { queue, connected: this.publishConnection.amqpConnection?.isConnected() });
349
393
  return channel?.checkQueue(queue);
350
394
  }
351
- async deleteQueue(queue) {
395
+ async deleteQueue(queue, connection) {
352
396
  RabbitMq.validateName('queue', queue);
353
- const channel = await this.assertChannel();
354
- logger_1.default.info('rabbit: deleting queue', { queue });
397
+ const channel = await this.assertChannel({ connection });
398
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info('rabbit: deleting queue', { queue });
355
399
  const deleteQueueRes = await channel.deleteQueue(queue);
356
- debug('queue deleted', deleteQueueRes);
400
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('queue deleted', deleteQueueRes);
357
401
  return deleteQueueRes;
358
402
  }
359
403
  async bindQueue(queue, exchange) {
360
- const channel = await this.assertChannel();
404
+ const channel = await this.assertChannel({ connection: this.publishConnection });
361
405
  await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
362
406
  return channel.bindQueue(queue, exchange, '');
363
407
  }
364
408
  async setupQueue(queueName, options) {
365
409
  let queue;
410
+ const connection = this.publishConnection;
366
411
  const localeOptions = {
367
412
  ...options,
368
413
  durable: true,
@@ -373,23 +418,23 @@ class RabbitMq {
373
418
  },
374
419
  };
375
420
  try {
376
- const channel = await this.assertChannel();
377
- debug('assertQueue->channel.addSetup', { queueName });
421
+ const channel = await this.assertChannel({ connection });
422
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('assertQueue->channel.addSetup', { queueName });
378
423
  await channel.addSetup(async (setupChannel) => {
379
424
  await setupChannel.assertQueue(queueName, localeOptions);
380
425
  });
381
- debug('assertQueue->channel.assertQueue', { queueName });
426
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('assertQueue->channel.assertQueue', { queueName });
382
427
  queue = await channel.assertQueue(queueName, localeOptions);
383
428
  }
384
429
  catch (e) {
385
- logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
430
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: assertQueue error', { queueName, options, error: e });
386
431
  if (!this.options?.dontRetryAssert) {
387
- debug('retrying assertQueue', { queueName });
388
- const channel = await this.assertChannel({ force: true });
389
- await this.deleteQueue(queueName);
390
- debug('retrying assertQueue->channel.addSetup', { queueName });
432
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue', { queueName });
433
+ const channel = await this.assertChannel({ force: true, connection });
434
+ await this.deleteQueue(queueName, connection);
435
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue->channel.addSetup', { queueName });
391
436
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
392
- debug('retrying assertQueue->channel.assertQueue', { queueName });
437
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue->channel.assertQueue', { queueName });
393
438
  queue = await channel.assertQueue(queueName, localeOptions);
394
439
  }
395
440
  else {
@@ -399,7 +444,7 @@ class RabbitMq {
399
444
  this.queues[queueName] = queue;
400
445
  return queue;
401
446
  }
402
- // TODO: Can be deleted after deleting the old consumers
447
+ // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
403
448
  static shouldUseQuorum(queueName) {
404
449
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
405
450
  if (envQuorumQueuesWhitelist === '*') {
@@ -412,22 +457,20 @@ class RabbitMq {
412
457
  return false;
413
458
  }
414
459
  async assertQueue(queueName, options) {
460
+ var _a;
415
461
  RabbitMq.validateName('queue', queueName);
416
462
  if (this.queues[queueName]) {
417
463
  delete this.queueSetupPromises[queueName];
418
464
  return this.queues[queueName];
419
465
  }
420
- if (this.queueSetupPromises[queueName]) {
421
- return this.queueSetupPromises[queueName];
422
- }
423
- this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
466
+ (_a = this.queueSetupPromises)[queueName] || (_a[queueName] = this.setupQueue(queueName, options));
424
467
  return this.queueSetupPromises[queueName];
425
468
  }
426
469
  saveConsumer(queue, callback, options) {
427
- const isConsumerExist = this.consumers.some((consumer) => consumer.queue === queue);
470
+ const isConsumerExist = this.consumersToRegister.some((consumer) => consumer.queue === queue);
428
471
  if (!isConsumerExist) {
429
- logger_1.default.info(`rabbit: consumer: ${queue} saved in consumer array`);
430
- this.consumers.push({
472
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: consumer: ${queue} saved in consumer array`);
473
+ this.consumersToRegister.push({
431
474
  queue,
432
475
  callback,
433
476
  options,
@@ -436,18 +479,21 @@ class RabbitMq {
436
479
  }
437
480
  // Used by the microservices to consume messages from the queue
438
481
  async consume(queue, callback, options) {
439
- // TODO: USE THE IMPLEMENTATION OF THE NEW CONSUME AND DELETE THE NEW AND OLD
440
- if (options?.isQuorumQueue !== false) {
441
- await this.assertVHost();
482
+ this.saveConsumerOld(queue, callback, options);
483
+ // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
484
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
485
+ this.saveConsumer(queue, callback, options);
486
+ const backoffConfig = (0, utils_1.getAssertVhostExponentialBackoffConfig)();
487
+ await (0, exponential_backoff_1.backOff)(() => this.assertVHost(), backoffConfig);
442
488
  await this.consumeNew(queue, callback, options);
443
489
  }
444
490
  await this.consumeOld(queue, callback, options);
445
491
  }
446
- // TODO: DELETE
492
+ // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
447
493
  async consumeNew(queue, callback, options) {
448
494
  await this.consumeFromRabbit(queue, callback, options);
449
495
  }
450
- // TODO: DELETE
496
+ // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
451
497
  async consumeOld(queue, callback, options) {
452
498
  await this.consumeFromRabbitOld(queue, callback, options);
453
499
  }
@@ -468,26 +514,23 @@ class RabbitMq {
468
514
  async consumeFromRabbit(queue, callback, options) {
469
515
  const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
470
516
  RabbitMq.validateName('queue', queue);
471
- this.saveConsumer(queue, callback, options);
472
517
  const uniqueId = (0, node_crypto_1.randomUUID)();
473
518
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
474
519
  if (useConsumeWithLock) {
475
520
  if (!this.redisLock) {
476
- throw new Error('Usage of consumeWithLock requires RedisInstance');
521
+ throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
477
522
  }
478
- logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
523
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
479
524
  }
480
- const channel = await this.getNewChannel({});
525
+ const channel = await this.getNewChannel({ connection: this.consumeConnection });
481
526
  return channel.addSetup(async (confirmChannel) => {
482
- const q = await this.assertQueue(queue, optionsWithDefaults);
527
+ await this.assertQueue(queue, optionsWithDefaults);
483
528
  await confirmChannel.prefetch(limit, false);
484
529
  const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
485
530
  if (!msg) {
486
531
  return null;
487
532
  }
488
- const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
489
- const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
490
- const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
533
+ const { [consts_1.TRACING_HEADER]: traceId, [consts_1.USER_TRACING_HEADER]: userId, [consts_1.AUTOMATION_ID_HEADER]: automationId } = msg.properties.headers ?? {};
491
534
  const parsedMessage = RabbitMq.parseMsg(msg);
492
535
  const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
493
536
  const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
@@ -503,7 +546,7 @@ class RabbitMq {
503
546
  ]);
504
547
  }
505
548
  catch (e) {
506
- logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
549
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: failed to setRabbitTrace', { userId, e });
507
550
  return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
508
551
  }
509
552
  }
@@ -529,29 +572,29 @@ class RabbitMq {
529
572
  return;
530
573
  }
531
574
  messageAcked = true;
532
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
575
+ await this.ack(confirmChannel, msg, true, releaseLock)(msg);
533
576
  };
534
577
  const localNack = async (_, nackOptions = {}) => {
535
578
  if (messageAcked) {
536
579
  return;
537
580
  }
538
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
581
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
539
582
  messageAcked = true;
540
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
583
+ await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
541
584
  };
542
585
  try {
543
- await callback(parsedMessage, localAck, localNack);
586
+ return await callback(parsedMessage, localAck, localNack);
544
587
  }
545
588
  catch (e) {
546
- await localNack(msg);
589
+ return localNack(msg);
547
590
  }
548
591
  }, types_1.CONSUMER_DEFAULT_OPTIONS);
549
592
  if (!consumerTag) {
550
- logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
593
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: failed to consume from queue ${queue}`);
551
594
  }
552
595
  else {
553
- logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
554
- this.consumersTags.push([confirmChannel, consumerTag]);
596
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: adding tag ${consumerTag} to the array.`);
597
+ this.consumersTags.set(queue, { channel: confirmChannel, consumerTag });
555
598
  }
556
599
  });
557
600
  }
@@ -560,11 +603,16 @@ class RabbitMq {
560
603
  const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
561
604
  RabbitMq.validateName('exchange', exchange);
562
605
  RabbitMq.validateName('queue', queue);
563
- const { limit, deadMessageTtl } = optionsWithDefaults;
564
- if (options?.isQuorumQueue !== false) {
565
- await this.assertVHost();
606
+ const { limit } = optionsWithDefaults;
607
+ // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
608
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
566
609
  await this.saveConsumer(queue, callback, options);
567
- const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
610
+ const backoffConfig = (0, utils_1.getAssertVhostExponentialBackoffConfig)();
611
+ await (0, exponential_backoff_1.backOff)(() => this.assertVHost(), backoffConfig);
612
+ const channel = await this.getNewChannel({
613
+ name: `consume-exchange-${exchange}-queue-${queue}`,
614
+ connection: this.consumeConnection,
615
+ });
568
616
  await channel.addSetup(async (c) => {
569
617
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
570
618
  await c.assertQueue(queue);
@@ -576,9 +624,12 @@ class RabbitMq {
576
624
  ]);
577
625
  });
578
626
  }
579
- // TODO: DELETE OLD
627
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
580
628
  await this.saveConsumerOld(queue, callback, options);
581
- const channelOld = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
629
+ const channelOld = await this.getNewChannelOld({
630
+ name: `consume-exchange-${exchange}-queue-${queue}-old`,
631
+ connection: this.oldConsumeConnection,
632
+ });
582
633
  await channelOld.addSetup(async (c) => {
583
634
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
584
635
  await c.assertQueue(queue);
@@ -591,35 +642,33 @@ class RabbitMq {
591
642
  });
592
643
  }
593
644
  // Used by the microservices to publish messages to the exchange
645
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
594
646
  async publish(exchange, content, customHeaders, isQuorumQueue = true) {
595
- // TODO: DELETE THE IF
596
- if (isQuorumQueue) {
597
- return (0, utils_1.wrapSetImmediate)(async () => {
598
- await this.assertVHost();
599
- RabbitMq.validateName('exchange', exchange);
600
- const channel = await this.assertChannel();
601
- await this.assertExchange(exchange);
602
- await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
603
- });
604
- }
605
- // TODO: DELETE THE OLD
606
- return (0, utils_1.wrapSetImmediate)(async () => {
647
+ await (0, promises_1.setImmediate)();
648
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
649
+ await this.assertVHost();
607
650
  RabbitMq.validateName('exchange', exchange);
608
- const channel = await this.assertChannelOld();
609
- await this.assertExchangeOld(exchange);
651
+ const channel = await this.assertChannel({ connection: this.publishConnection });
652
+ await this.assertExchange(exchange, this.publishConnection);
610
653
  await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
611
- });
654
+ return;
655
+ }
656
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
657
+ RabbitMq.validateName('exchange', exchange);
658
+ const channel = await this.assertChannelOld({ connection: this.oldPublishConnection });
659
+ await this.assertExchangeOld(exchange, this.oldPublishConnection);
660
+ await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
612
661
  }
613
662
  // Used by the microservices to send messages to the queue
663
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
614
664
  async sendToQueue(queue, content, options, customHeaders, isQuorumQueue = true) {
615
- // TODO: DELETE THE IF AND THE OLD
616
- if (isQuorumQueue) {
665
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
617
666
  try {
618
667
  await this.assertVHost();
619
- await this.assertChannel();
668
+ await this.assertChannel({ connection: this.publishConnection });
620
669
  }
621
670
  catch (e) {
622
- logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
671
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
623
672
  throw e;
624
673
  }
625
674
  try {
@@ -627,110 +676,127 @@ class RabbitMq {
627
676
  await this.assertQueue(queue, options);
628
677
  }
629
678
  catch (e) {
630
- logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
679
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
631
680
  throw e;
632
681
  }
633
682
  try {
634
- const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
635
- debug(`rabbit: sending to queue ${queue}`, { res });
683
+ const res = await this.publishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
684
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug(`rabbit: sending to queue ${queue}`, { res });
636
685
  return res;
637
686
  }
638
687
  catch (e) {
639
688
  const isConnected = await this.isConnected();
640
- logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
689
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
641
690
  throw e;
642
691
  }
643
692
  }
644
693
  else {
645
694
  try {
646
- await this.assertChannelOld();
695
+ await this.assertChannelOld({ connection: this.oldPublishConnection });
647
696
  }
648
697
  catch (e) {
649
- logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
698
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
699
+ throw e;
700
+ }
701
+ try {
702
+ RabbitMq.validateName('queue', queue);
703
+ await this.assertQueueOld(queue, options);
704
+ }
705
+ catch (e) {
706
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
707
+ throw e;
708
+ }
709
+ try {
710
+ const res = await this.oldPublishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
711
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug(`rabbit: sending to queue ${queue}`, { res });
712
+ return res;
713
+ }
714
+ catch (e) {
715
+ const isConnected = await this.isConnectedOld();
716
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
650
717
  throw e;
651
718
  }
652
- }
653
- try {
654
- RabbitMq.validateName('queue', queue);
655
- await this.assertQueueOld(queue, options);
656
- }
657
- catch (e) {
658
- logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
659
- throw e;
660
- }
661
- try {
662
- const res = await this.oldChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
663
- debug(`rabbit: sending to queue ${queue}`, { res });
664
- return res;
665
- }
666
- catch (e) {
667
- const isConnected = await this.isConnected();
668
- logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
669
- throw e;
670
719
  }
671
720
  }
672
721
  async isConnected() {
673
- const connection = await this.getConnection();
674
- const isConnected = connection.isConnected();
675
- if (!isConnected) {
676
- logger_1.default.error('rabbit: isConnected - false');
677
- return false;
678
- }
679
- const channel = await this.assertChannel();
680
- try {
681
- await Promise.all([
682
- channel.waitForConnect(),
683
- ...this.consumers.map((c) => channel.checkQueue(c.queue)),
684
- ]);
685
- }
686
- catch (e) {
687
- logger_1.default.error('rabbit: isConnected - false');
688
- return false;
722
+ let isConnected = true;
723
+ // TODO:[QUORUM-PHASE-3] Remove the condition
724
+ if (!this.gracefulShutdownStarted) {
725
+ if (DISABLE_QUORUM_QUEUES_CONSUME !== 'true' || DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
726
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: start is connected');
727
+ const [consumeConnection, publishConnection] = await Promise.all([
728
+ this.getConnection(this.consumeConnection),
729
+ this.getConnection(this.publishConnection),
730
+ ]);
731
+ isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
732
+ if (!isConnected) {
733
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: isConnected - false');
734
+ return false;
735
+ }
736
+ try {
737
+ const unRegisteredConsumers = this.consumersToRegister.filter((c) => !this.consumersTags.get(c.queue));
738
+ if (unRegisteredConsumers.length > 0) {
739
+ const queueNames = unRegisteredConsumers.map((c) => c.queue);
740
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: found unregistered consumers for queues', {
741
+ count: queueNames.length,
742
+ queues: queueNames,
743
+ });
744
+ throw new rabbitError_1.default('Found unregistered consumers');
745
+ }
746
+ const channel = await this.assertChannel({ connection: this.publishConnection });
747
+ await channel.waitForConnect();
748
+ await Promise.all(this.consumersToRegister.map((c) => channel.checkQueue(c.queue)));
749
+ }
750
+ catch (e) {
751
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: isConnected - false', { msg: e.message });
752
+ return false;
753
+ }
754
+ }
755
+ // TODO:[QUORUM-PHASE-3] Delete the old is connected and adjust the return value to return true
756
+ isConnected = await this.isConnectedOld();
689
757
  }
690
- logger_1.default.info('rabbit: isConnected - true');
691
- return true;
758
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug(`rabbit: isConnected - ${isConnected}`);
759
+ return isConnected;
692
760
  }
693
761
  async gracefulShutdown(signal) {
694
- // TODO: DELETE OLD
695
- const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
696
- logger_1.default.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
697
- const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
698
- const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
762
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation they are not needed anymore
763
+ this.gracefulShutdownStarted = true;
764
+ const tagsNumber = this.consumersTags.size + this.oldConsumersTags.size;
765
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
766
+ const cancelTagPromises = [...this.consumersTags].map(([, { channel, consumerTag }]) => channel.cancel(consumerTag));
767
+ const cancelTagPromisesOld = [...this.oldConsumersTags].map(([, { channel, consumerTag }]) => channel.cancel(consumerTag));
699
768
  // Clean the array to avoid race
700
- this.consumersTags = [];
701
- this.oldConsumersTags = [];
769
+ this.consumersTags.clear();
770
+ this.oldConsumersTags.clear();
702
771
  const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
703
772
  const rejected = results.filter((p) => p.status === 'rejected');
704
773
  if (rejected.length > 0) {
705
- logger_1.default.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
774
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
706
775
  }
707
776
  else {
708
- logger_1.default.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
777
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
709
778
  }
710
779
  }
711
780
  async consumeFromRabbitOld(queue, callback, options) {
712
781
  const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
713
782
  RabbitMq.validateName('queue', queue);
714
- this.saveConsumerOld(queue, callback, options);
715
783
  const uniqueId = (0, node_crypto_1.randomUUID)();
716
784
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
717
785
  if (useConsumeWithLock) {
718
786
  if (!this.redisLock) {
719
- throw new Error('Usage of consumeWithLock requires RedisInstance');
787
+ throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
720
788
  }
721
- logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
789
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
722
790
  }
723
- const channel = await this.getNewChannelOld({});
791
+ const channel = await this.getNewChannelOld({ connection: this.oldConsumeConnection });
724
792
  return channel.addSetup(async (confirmChannel) => {
725
- const q = await this.assertQueueOld(queue, optionsWithDefaults);
793
+ await this.assertQueueOld(queue, optionsWithDefaults);
726
794
  await confirmChannel.prefetch(limit, false);
727
795
  const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
728
796
  if (!msg) {
729
797
  return null;
730
798
  }
731
- const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
732
- const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
733
- const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
799
+ const { [consts_1.TRACING_HEADER]: traceId, [consts_1.USER_TRACING_HEADER]: userId, [consts_1.AUTOMATION_ID_HEADER]: automationId } = msg.properties.headers ?? {};
734
800
  const parsedMessage = RabbitMq.parseMsg(msg);
735
801
  const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
736
802
  const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
@@ -746,7 +812,7 @@ class RabbitMq {
746
812
  ]);
747
813
  }
748
814
  catch (e) {
749
- logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
815
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: failed to setRabbitTrace', { userId, e });
750
816
  return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
751
817
  }
752
818
  }
@@ -772,139 +838,144 @@ class RabbitMq {
772
838
  return;
773
839
  }
774
840
  messageAcked = true;
775
- return this.ack(confirmChannel, msg, true, releaseLock)(msg);
841
+ await this.ack(confirmChannel, msg, true, releaseLock)(msg);
776
842
  };
777
843
  const localNack = async (_, nackOptions = {}) => {
778
844
  if (messageAcked) {
779
845
  return;
780
846
  }
781
- debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
847
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
782
848
  messageAcked = true;
783
- return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
849
+ await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
784
850
  };
785
851
  try {
786
- await callback(parsedMessage, localAck, localNack);
852
+ return await callback(parsedMessage, localAck, localNack);
787
853
  }
788
854
  catch (e) {
789
- await localNack(msg);
855
+ return localNack(msg);
790
856
  }
791
857
  }, types_1.CONSUMER_DEFAULT_OPTIONS);
792
858
  if (!consumerTag) {
793
- logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
859
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: failed to consume from queue ${queue} old`);
794
860
  }
795
861
  else {
796
- logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
797
- this.oldConsumersTags.push([confirmChannel, consumerTag]);
862
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").info(`rabbit: adding tag ${consumerTag} to the array old`);
863
+ this.oldConsumersTags.set(queue, { channel: confirmChannel, consumerTag });
798
864
  }
799
865
  });
800
866
  }
801
- // TODO: DELETE OLD PROPERTIES UNDER THIS LINE
802
- async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
803
- let connection;
867
+ // TODO: [QUORUM-PHASE-3] Delete all the function under this line.
868
+ async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connection, }) {
869
+ let localConnection;
804
870
  try {
805
- connection = await this.getConnectionOld();
871
+ localConnection = await this.getConnectionOld(connection);
806
872
  }
807
873
  catch (e) {
808
- logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
874
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: error on get connection for new channel ${name} `, { e });
809
875
  throw e;
810
876
  }
811
- const channel = connection.createChannel({ ...options });
812
- (0, events_1.once)(channel, 'close').then((args) => {
813
- logger_1.default.error(`rabbit: channel ${name} closed`);
877
+ if (!localConnection) {
878
+ throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
879
+ }
880
+ const channel = localConnection?.createChannel({ ...options });
881
+ (0, node_events_1.once)(channel, 'close').then((args) => {
882
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: channel ${name} closed`);
814
883
  onClose?.(args);
815
884
  });
816
885
  try {
817
- await (0, events_1.once)(channel, 'connect');
818
- debug(`rabbit: channel ${name} CONNECTED`);
886
+ await (0, node_events_1.once)(channel, 'connect');
887
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug(`rabbit: channel ${name} CONNECTED`);
819
888
  return channel;
820
889
  }
821
890
  catch (err) {
822
- logger_1.default.error(`rabbit: channel error ${name} error`, { err });
891
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error(`rabbit: channel error ${name} error`, { err });
823
892
  throw err;
824
893
  }
825
894
  }
826
- async getConnectionOld() {
827
- return new Promise(async (resolve, reject) => {
828
- if (this.oldBlockReconnect) {
829
- debug('rabbit: block reconnect');
895
+ async getConnectionOld(connection) {
896
+ const { amqpConnection: connectionLocal, creatingConnection, connectionCreatedEventName, connectionFailedEventName, blockReconnect, } = connection;
897
+ if (blockReconnect) {
898
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: block reconnect');
899
+ // @ts-expect-error we are returning undefined while the function clearly expects a connection.
900
+ return undefined;
901
+ }
902
+ if (connectionLocal !== null) {
903
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
904
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection - is connected');
830
905
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
831
906
  // @ts-ignore
832
- return resolve();
833
- }
834
- if (this.oldConnection !== null) {
835
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
836
- debug('rabbit: connection - is connected');
837
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
838
- // @ts-ignore
839
- return resolve(this.oldConnection);
840
- }
841
- debug('rabbit: connection - reconnecting');
907
+ return connectionLocal;
842
908
  }
843
- if (this.oldCreatingConnection) {
844
- debug('rabbit: creating connection emi');
845
- this.oldEm.once(consts_1.CONNECTION_CREATED_CONST, resolve);
846
- this.oldEm.once(consts_1.CONNECTION_FAILED_CONST, reject);
847
- return;
909
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection - reconnecting');
910
+ }
911
+ if (creatingConnection) {
912
+ const [event, value] = await Promise.race([connectionCreatedEventName, connectionFailedEventName].map((e) => (0, node_events_1.once)(this.oldEm, e).then(([result]) => [e, result])));
913
+ if (event === connectionCreatedEventName) {
914
+ return value;
848
915
  }
849
- this.oldCreatingConnection = true;
850
- let isResolved = false;
851
- // It is import to use it as a function and not as a variable
852
- // because of k8s changes the env variables
853
- // and we want to use the new values
854
- const findServers = () => {
855
- const userName = process.env.RABBITMQ_USERNAME || 'guest';
856
- const password = process.env.RABBITMQ_PASSWORD || 'guest';
857
- const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
858
- debug('rabbit: creating connection', { host, userName, HEARTBEAT });
859
- return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
860
- };
861
- const defaultUrls = findServers();
862
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
863
- findServers,
864
- });
865
- this.oldConnection = connection;
866
- this.oldConnection.on('error', (err) => {
867
- logger_1.default.error('rabbit: connection error', { err });
868
- if (!isResolved) {
869
- isResolved = true;
870
- reject(err);
871
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
872
- }
873
- });
874
- this.oldConnection.on('connectFailed', (err) => {
875
- this.oldConsumersTags = [];
876
- logger_1.default.error('rabbit: connection connectFailed', { err });
877
- if (!isResolved) {
878
- isResolved = true;
879
- reject(err);
880
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
881
- }
882
- });
883
- this.oldConnection.on('disconnect', ({ err }) => {
884
- this.oldConsumersTags = [];
885
- debug('rabbit: connection closed');
886
- if (this.options?.disableReconnect) {
887
- logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
888
- this.oldBlockReconnect = true;
889
- }
890
- else {
891
- logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
892
- }
893
- });
894
- this.oldConnection.once('connect', async () => {
895
- debug('rabbit: connection established');
896
- this.oldCreatingConnection = false;
897
- this.oldEm.emit(consts_1.CONNECTION_CREATED_CONST, connection);
916
+ throw value;
917
+ }
918
+ connection.creatingConnection = true;
919
+ let isResolved = false;
920
+ // It is import to use it as a function and not as a variable
921
+ // because of k8s changes the env variables
922
+ // and we want to use the new values
923
+ const findServers = () => {
924
+ const userName = process.env.RABBITMQ_USERNAME || 'guest';
925
+ const password = process.env.RABBITMQ_PASSWORD || 'guest';
926
+ const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
927
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: creating connection', { host, userName, HEARTBEAT });
928
+ return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
929
+ };
930
+ const defaultUrls = findServers();
931
+ const newConnection = await (0, amqp_connection_manager_1.connect)(defaultUrls, { findServers });
932
+ connection.amqpConnection = newConnection;
933
+ const { promise, reject, resolve } = (0, utils_1.createDeferredPromise)();
934
+ newConnection.on('error', (err) => {
935
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").error('rabbit: connection error', { err });
936
+ if (!isResolved) {
898
937
  isResolved = true;
899
- resolve(connection);
900
- });
938
+ reject(err);
939
+ this.oldEm.emit(connectionFailedEventName, err);
940
+ }
941
+ });
942
+ newConnection.on('connectFailed', (err) => {
943
+ this.oldConsumersTags.clear();
944
+ if (typeof err.url === 'string') {
945
+ err.url = this.maskURL(err.url);
946
+ }
947
+ logger_1.default.error('rabbit: connection connectFailed', { err });
948
+ if (!isResolved) {
949
+ isResolved = true;
950
+ reject(err);
951
+ this.oldEm.emit(connectionFailedEventName, err);
952
+ }
953
+ });
954
+ newConnection.on('disconnect', ({ err }) => {
955
+ this.oldConsumersTags.clear();
956
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection closed');
957
+ if (this.options?.disableReconnect) {
958
+ logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
959
+ connection.blockReconnect = true;
960
+ }
961
+ else {
962
+ logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
963
+ }
901
964
  });
965
+ newConnection.once('connect', async () => {
966
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: connection established');
967
+ connection.creatingConnection = false;
968
+ this.oldEm.emit(connectionCreatedEventName, newConnection);
969
+ isResolved = true;
970
+ resolve(newConnection);
971
+ });
972
+ return promise;
902
973
  }
903
974
  saveConsumerOld(queue, callback, options) {
904
- const isConsumerExist = this.oldConsumers.some((consumer) => consumer.queue === queue);
975
+ const isConsumerExist = this.oldConsumersToRegister.some((consumer) => consumer.queue === queue);
905
976
  if (!isConsumerExist) {
906
977
  logger_1.default.info(`rabbit: consumer: ${queue} saved in consumer array`);
907
- this.oldConsumers.push({
978
+ this.oldConsumersToRegister.push({
908
979
  queue,
909
980
  callback,
910
981
  options,
@@ -912,19 +983,18 @@ class RabbitMq {
912
983
  }
913
984
  }
914
985
  async assertQueueOld(queueName, options) {
986
+ var _a;
915
987
  RabbitMq.validateName('queue', queueName);
916
988
  if (this.oldQueues[queueName]) {
917
989
  delete this.oldQueueSetupPromises[queueName];
918
990
  return this.oldQueues[queueName];
919
991
  }
920
- if (this.oldQueueSetupPromises[queueName]) {
921
- return this.oldQueueSetupPromises[queueName];
922
- }
923
- this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
992
+ (_a = this.oldQueueSetupPromises)[queueName] || (_a[queueName] = this.setupQueueOld(queueName, options));
924
993
  return this.oldQueueSetupPromises[queueName];
925
994
  }
926
995
  async setupQueueOld(queueName, options) {
927
996
  let queue;
997
+ const connection = this.oldPublishConnection;
928
998
  const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
929
999
  const localeOptions = {
930
1000
  ...options,
@@ -936,21 +1006,21 @@ class RabbitMq {
936
1006
  },
937
1007
  };
938
1008
  try {
939
- const channel = await this.assertChannelOld();
940
- debug('assertQueue->channel.addSetup', { queueName });
1009
+ const channel = await this.assertChannelOld({ connection });
1010
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('assertQueue->channel.addSetup', { queueName });
941
1011
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
942
- debug('assertQueue->channel.assertQueue', { queueName });
1012
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('assertQueue->channel.assertQueue', { queueName });
943
1013
  queue = await channel.assertQueue(queueName, localeOptions);
944
1014
  }
945
1015
  catch (e) {
946
1016
  logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
947
1017
  if (!this.options?.dontRetryAssert) {
948
- debug('retrying assertQueue', { queueName });
949
- const channel = await this.assertChannelOld({ force: true });
950
- await this.deleteQueueOld(queueName);
951
- debug('retrying assertQueue->channel.addSetup', { queueName });
1018
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue', { queueName });
1019
+ const channel = await this.assertChannelOld({ force: true, connection });
1020
+ await this.deleteQueueOld(queueName, connection);
1021
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue->channel.addSetup', { queueName });
952
1022
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
953
- debug('retrying assertQueue->channel.assertQueue', { queueName });
1023
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('retrying assertQueue->channel.assertQueue', { queueName });
954
1024
  queue = await channel.assertQueue(queueName, localeOptions);
955
1025
  }
956
1026
  else {
@@ -960,37 +1030,41 @@ class RabbitMq {
960
1030
  this.oldQueues[queueName] = queue;
961
1031
  return queue;
962
1032
  }
963
- async assertChannelOld({ force = false } = {}) {
964
- if (!this.oldPublishChannelSetupPromise) {
965
- this.oldPublishChannelSetupPromise = new Promise(async (resolve, reject) => {
966
- if (this.oldChannel && !force) {
967
- return resolve(this.oldChannel);
968
- }
969
- try {
970
- const channel = await this.getNewChannelOld({});
971
- channel.on('error', (err) => {
972
- logger_1.default.error('rabbit: channel error', { err });
973
- });
974
- this.oldChannel = channel;
975
- resolve(channel);
976
- }
977
- catch (e) {
978
- reject(e);
979
- }
1033
+ async assertChannelOld({ force = false, connection }) {
1034
+ if (this.oldPublishChannelSetupPromise) {
1035
+ return this.oldPublishChannelSetupPromise;
1036
+ }
1037
+ const { promise, resolve, reject } = (0, utils_1.createDeferredPromise)();
1038
+ this.oldPublishChannelSetupPromise = promise;
1039
+ if (this.oldPublishChannel && !force) {
1040
+ resolve(this.oldPublishChannel);
1041
+ return promise;
1042
+ }
1043
+ try {
1044
+ const channel = await this.getNewChannelOld({ connection });
1045
+ channel.on('error', (err) => {
1046
+ logger_1.default.error('rabbit: channel error', { err });
980
1047
  });
1048
+ if (this.oldPublishConnection === connection) {
1049
+ this.oldPublishChannel = channel;
1050
+ }
1051
+ resolve(channel);
981
1052
  }
982
- return this.oldPublishChannelSetupPromise;
1053
+ catch (e) {
1054
+ reject(e);
1055
+ }
1056
+ return promise;
983
1057
  }
984
- async deleteQueueOld(queue) {
1058
+ async deleteQueueOld(queue, connection) {
985
1059
  RabbitMq.validateName('queue', queue);
986
- const channel = await this.assertChannelOld();
1060
+ const channel = await this.assertChannelOld({ connection });
987
1061
  logger_1.default.info('rabbit: deleting queue', { queue });
988
1062
  const deleteQueueRes = await channel.deleteQueue(queue);
989
- debug('queue deleted', deleteQueueRes);
1063
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('queue deleted', deleteQueueRes);
990
1064
  return deleteQueueRes;
991
1065
  }
992
- async assertExchangeOld(exchangeName, options) {
993
- const channel = await this.assertChannelOld();
1066
+ async assertExchangeOld(exchangeName, connection) {
1067
+ const channel = await this.assertChannelOld({ connection });
994
1068
  if (this.oldExchanges[exchangeName]) {
995
1069
  delete this.oldAssertExchangePromises[exchangeName];
996
1070
  return this.oldExchanges[exchangeName];
@@ -1002,7 +1076,42 @@ class RabbitMq {
1002
1076
  this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
1003
1077
  return this.oldExchanges[exchangeName];
1004
1078
  }
1079
+ async isConnectedOld() {
1080
+ if (!this.gracefulShutdownStarted) {
1081
+ __classPrivateFieldGet(this, _RabbitMq_logger, "f").debug('rabbit: start is connected old');
1082
+ const [oldConsumeConnection, oldPublishConnection] = await Promise.all([
1083
+ this.getConnectionOld(this.oldConsumeConnection),
1084
+ this.getConnectionOld(this.oldPublishConnection),
1085
+ ]);
1086
+ const isConnected = oldConsumeConnection.isConnected() && oldPublishConnection.isConnected();
1087
+ if (!isConnected) {
1088
+ logger_1.default.error('rabbit: isConnected old - false');
1089
+ return false;
1090
+ }
1091
+ try {
1092
+ const unRegisteredConsumersOld = this.oldConsumersToRegister.filter((c) => !this.oldConsumersTags.get(c.queue));
1093
+ if (unRegisteredConsumersOld.length > 0) {
1094
+ const queueNames = unRegisteredConsumersOld.map((c) => c.queue);
1095
+ logger_1.default.error('rabbit: found unregistered consumers for queues old', {
1096
+ count: queueNames.length,
1097
+ queues: queueNames,
1098
+ });
1099
+ throw new rabbitError_1.default('Found unregistered consumers old');
1100
+ }
1101
+ const channelOld = await this.assertChannelOld({ connection: this.oldPublishConnection });
1102
+ await channelOld.waitForConnect();
1103
+ await Promise.all(this.oldConsumersToRegister.map((c) => channelOld.checkQueue(c.queue)));
1104
+ }
1105
+ catch (e) {
1106
+ logger_1.default.error('rabbit: isConnected - false old', { msg: e.message });
1107
+ return false;
1108
+ }
1109
+ }
1110
+ return true;
1111
+ }
1005
1112
  }
1113
+ _RabbitMq_logger = new WeakMap();
1006
1114
  exports.default = RabbitMq;
1007
1115
  var celery_1 = require("./lib/celery");
1008
1116
  Object.defineProperty(exports, "sendCeleryTaskViaHttp", { enumerable: true, get: function () { return celery_1.sendCeleryTaskViaHttp; } });
1117
+ //# sourceMappingURL=index.js.map