@autofleet/rabbit 3.3.0-beta.10 → 3.3.0-beta.2
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/.nvmrc +1 -1
- package/dist/index.d.ts +13 -34
- package/dist/index.js +124 -498
- package/dist/lib/consts.d.ts +4 -2
- package/dist/lib/consts.js +6 -3
- package/dist/lib/types.d.ts +7 -1
- package/package.json +1 -1
- package/src/index.ts +159 -597
- package/src/lib/consts.ts +5 -2
- package/src/lib/types.ts +8 -2
package/dist/index.js
CHANGED
|
@@ -56,57 +56,10 @@ class RabbitMq {
|
|
|
56
56
|
},
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
constructor(options
|
|
59
|
+
constructor(options, redisConfig) {
|
|
60
60
|
this.DISCONNECT_MSG = 'rabbit: connection disconnect';
|
|
61
61
|
this.RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
62
62
|
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
63
|
this.shouldConsumeMessageByTimestamp = async (msg) => {
|
|
111
64
|
if (msg) {
|
|
112
65
|
const { properties: { headers } } = msg;
|
|
@@ -136,11 +89,11 @@ class RabbitMq {
|
|
|
136
89
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
137
90
|
if (channel && msg) {
|
|
138
91
|
if (!skipRetry
|
|
139
|
-
&& (!msg.properties.headers
|
|
140
|
-
|| parseInt(msg.properties.headers
|
|
92
|
+
&& (!msg.properties.headers[consts_1.RETRY_HEADER]
|
|
93
|
+
|| parseInt(msg.properties.headers[consts_1.RETRY_HEADER], 10) < options.retries)) {
|
|
141
94
|
await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
|
|
142
95
|
...msg.properties.headers,
|
|
143
|
-
[consts_1.RETRY_HEADER]: msg.properties.headers
|
|
96
|
+
[consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
|
|
144
97
|
? msg.properties.headers[consts_1.RETRY_HEADER] + 1
|
|
145
98
|
: 1,
|
|
146
99
|
});
|
|
@@ -149,7 +102,7 @@ class RabbitMq {
|
|
|
149
102
|
const deadQueue = `${queue}-dead`;
|
|
150
103
|
await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
|
|
151
104
|
...msg.properties.headers,
|
|
152
|
-
[consts_1.RETRY_HEADER]: msg.properties.headers
|
|
105
|
+
[consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
|
|
153
106
|
? msg.properties.headers[consts_1.RETRY_HEADER] + 1
|
|
154
107
|
: 1,
|
|
155
108
|
});
|
|
@@ -164,10 +117,22 @@ class RabbitMq {
|
|
|
164
117
|
}
|
|
165
118
|
};
|
|
166
119
|
this.em = new events_1.EventEmitter();
|
|
167
|
-
this.
|
|
120
|
+
this.publishChannel = null;
|
|
168
121
|
this.publishChannelSetupPromise = null;
|
|
169
|
-
this.
|
|
170
|
-
|
|
122
|
+
this.connectionsMap = {
|
|
123
|
+
[consts_1.ConnectionPurpose.Consume]: {
|
|
124
|
+
connection: null,
|
|
125
|
+
creatingConnection: false,
|
|
126
|
+
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
127
|
+
connectionFailedEventName: 'consumeConnectionFailed',
|
|
128
|
+
},
|
|
129
|
+
[consts_1.ConnectionPurpose.Publish]: {
|
|
130
|
+
connection: null,
|
|
131
|
+
creatingConnection: false,
|
|
132
|
+
connectionCreatedEventName: 'publishConnectionCreated',
|
|
133
|
+
connectionFailedEventName: 'publishConnectionFailed',
|
|
134
|
+
},
|
|
135
|
+
};
|
|
171
136
|
this.exchanges = {};
|
|
172
137
|
this.queues = {};
|
|
173
138
|
this.queueSetupPromises = {};
|
|
@@ -188,43 +153,32 @@ class RabbitMq {
|
|
|
188
153
|
await this.gracefulShutdown('SIGINT');
|
|
189
154
|
});
|
|
190
155
|
}
|
|
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
156
|
}
|
|
204
|
-
async getConnection() {
|
|
157
|
+
async getConnection(connectionPurpose) {
|
|
205
158
|
return new Promise(async (resolve, reject) => {
|
|
159
|
+
const { connection, creatingConnection, connectionCreatedEventName, connectionFailedEventName, } = this.connectionsMap[connectionPurpose];
|
|
206
160
|
if (this.blockReconnect) {
|
|
207
161
|
debug('rabbit: block reconnect');
|
|
208
162
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
209
163
|
// @ts-ignore
|
|
210
164
|
return resolve();
|
|
211
165
|
}
|
|
212
|
-
if (
|
|
213
|
-
if (this.options?.disableReconnect ||
|
|
166
|
+
if (connection !== null) {
|
|
167
|
+
if (this.options?.disableReconnect || connection?.isConnected()) {
|
|
214
168
|
debug('rabbit: connection - is connected');
|
|
215
169
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
216
170
|
// @ts-ignore
|
|
217
|
-
return resolve(
|
|
171
|
+
return resolve(connection);
|
|
218
172
|
}
|
|
219
173
|
debug('rabbit: connection - reconnecting');
|
|
220
174
|
}
|
|
221
|
-
if (
|
|
175
|
+
if (creatingConnection) {
|
|
222
176
|
debug('rabbit: creating connection emi');
|
|
223
|
-
this.em.once(
|
|
224
|
-
this.em.once(
|
|
177
|
+
this.em.once(connectionCreatedEventName, resolve);
|
|
178
|
+
this.em.once(connectionFailedEventName, reject);
|
|
225
179
|
return;
|
|
226
180
|
}
|
|
227
|
-
this.creatingConnection = true;
|
|
181
|
+
this.connectionsMap[connectionPurpose].creatingConnection = true;
|
|
228
182
|
let isResolved = false;
|
|
229
183
|
// It is import to use it as a function and not as a variable
|
|
230
184
|
// because of k8s changes the env variables
|
|
@@ -234,32 +188,32 @@ class RabbitMq {
|
|
|
234
188
|
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
235
189
|
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
236
190
|
debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
237
|
-
return [`amqp://${userName}:${password}@${host}
|
|
191
|
+
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
238
192
|
};
|
|
239
193
|
const defaultUrls = findServers();
|
|
240
|
-
const
|
|
194
|
+
const newConnection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
|
|
241
195
|
findServers,
|
|
242
196
|
});
|
|
243
|
-
this.connection =
|
|
244
|
-
|
|
197
|
+
this.connectionsMap[connectionPurpose].connection = newConnection;
|
|
198
|
+
logger_1.default.info(`rabbit: created new connection ${connectionPurpose}`);
|
|
199
|
+
newConnection.on('error', (err) => {
|
|
245
200
|
logger_1.default.error('rabbit: connection error', { err });
|
|
246
201
|
if (!isResolved) {
|
|
247
202
|
isResolved = true;
|
|
248
203
|
reject(err);
|
|
249
|
-
this.em.emit(
|
|
204
|
+
this.em.emit(connectionFailedEventName, err);
|
|
250
205
|
}
|
|
251
206
|
});
|
|
252
|
-
|
|
207
|
+
newConnection.on('connectFailed', (err) => {
|
|
253
208
|
this.consumersTags = [];
|
|
254
|
-
logger_1.default.error('rabbit: connection connectFailed', { err
|
|
209
|
+
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
255
210
|
if (!isResolved) {
|
|
256
211
|
isResolved = true;
|
|
257
212
|
reject(err);
|
|
258
|
-
this.em.emit(
|
|
213
|
+
this.em.emit(connectionFailedEventName, err);
|
|
259
214
|
}
|
|
260
215
|
});
|
|
261
|
-
|
|
262
|
-
// this.channel = null;
|
|
216
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
263
217
|
this.consumersTags = [];
|
|
264
218
|
debug('rabbit: connection closed');
|
|
265
219
|
if (this.options?.disableReconnect) {
|
|
@@ -270,24 +224,26 @@ class RabbitMq {
|
|
|
270
224
|
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
271
225
|
}
|
|
272
226
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this.
|
|
276
|
-
this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
|
|
227
|
+
newConnection.once('connect', async () => {
|
|
228
|
+
this.connectionsMap[connectionPurpose].creatingConnection = false;
|
|
229
|
+
this.em.emit(connectionCreatedEventName, newConnection);
|
|
277
230
|
isResolved = true;
|
|
278
|
-
resolve(
|
|
231
|
+
resolve(newConnection);
|
|
279
232
|
});
|
|
280
233
|
});
|
|
281
234
|
}
|
|
282
|
-
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}
|
|
235
|
+
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connectionPurpose = consts_1.ConnectionPurpose.Consume, }) {
|
|
283
236
|
let connection;
|
|
284
237
|
try {
|
|
285
|
-
connection = await this.getConnection();
|
|
238
|
+
connection = await this.getConnection(connectionPurpose);
|
|
286
239
|
}
|
|
287
240
|
catch (e) {
|
|
288
241
|
logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
289
242
|
throw e;
|
|
290
243
|
}
|
|
244
|
+
if (!connection) {
|
|
245
|
+
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
246
|
+
}
|
|
291
247
|
const channel = connection.createChannel({ ...options });
|
|
292
248
|
(0, events_1.once)(channel, 'close').then((args) => {
|
|
293
249
|
logger_1.default.error(`rabbit: channel ${name} closed`);
|
|
@@ -303,18 +259,22 @@ class RabbitMq {
|
|
|
303
259
|
throw err;
|
|
304
260
|
}
|
|
305
261
|
}
|
|
306
|
-
async assertChannel({ force = false
|
|
262
|
+
async assertChannel({ force = false, connectionPurpose = consts_1.ConnectionPurpose.Consume }) {
|
|
263
|
+
debug('rabbit: start assert channel', { connectionPurpose, publishPromise: this.publishChannelSetupPromise, channel: this.publishChannel });
|
|
307
264
|
if (!this.publishChannelSetupPromise) {
|
|
308
265
|
this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
|
|
309
|
-
if (this.
|
|
310
|
-
return resolve(this.
|
|
266
|
+
if (this.publishChannel && !force) {
|
|
267
|
+
return resolve(this.publishChannel);
|
|
311
268
|
}
|
|
312
269
|
try {
|
|
313
|
-
const channel = await this.getNewChannel({});
|
|
270
|
+
const channel = await this.getNewChannel({ connectionPurpose });
|
|
271
|
+
debug('rabbit: new channel got', { connectionPurpose, channel: this.publishChannel });
|
|
314
272
|
channel.on('error', (err) => {
|
|
315
273
|
logger_1.default.error('rabbit: channel error', { err });
|
|
316
274
|
});
|
|
317
|
-
|
|
275
|
+
if (connectionPurpose === consts_1.ConnectionPurpose.Publish) {
|
|
276
|
+
this.publishChannel = channel;
|
|
277
|
+
}
|
|
318
278
|
resolve(channel);
|
|
319
279
|
}
|
|
320
280
|
catch (e) {
|
|
@@ -324,8 +284,8 @@ class RabbitMq {
|
|
|
324
284
|
}
|
|
325
285
|
return this.publishChannelSetupPromise;
|
|
326
286
|
}
|
|
327
|
-
async assertExchange(exchangeName, options) {
|
|
328
|
-
const channel = await this.assertChannel();
|
|
287
|
+
async assertExchange(exchangeName, options = { connectionPurpose: consts_1.ConnectionPurpose.Consume }) {
|
|
288
|
+
const channel = await this.assertChannel({ connectionPurpose: options.connectionPurpose });
|
|
329
289
|
if (this.exchanges[exchangeName]) {
|
|
330
290
|
delete this.assertExchangePromises[exchangeName];
|
|
331
291
|
return this.exchanges[exchangeName];
|
|
@@ -337,47 +297,46 @@ class RabbitMq {
|
|
|
337
297
|
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
338
298
|
return this.exchanges[exchangeName];
|
|
339
299
|
}
|
|
340
|
-
|
|
341
|
-
async getQueueLength(queue) {
|
|
300
|
+
async getQueueLength(queue, connectionPurpose = consts_1.ConnectionPurpose.Consume) {
|
|
342
301
|
RabbitMq.validateName('queue', queue);
|
|
343
|
-
const {
|
|
344
|
-
|
|
345
|
-
|
|
302
|
+
const { connection } = this.connectionsMap[connectionPurpose];
|
|
303
|
+
const { publishChannel } = this;
|
|
304
|
+
if (!publishChannel) {
|
|
305
|
+
throw new Error('channel is not defined');
|
|
346
306
|
}
|
|
347
|
-
debug('rabbit: getting queue length', { queue, connected:
|
|
348
|
-
return
|
|
307
|
+
debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
|
|
308
|
+
return publishChannel?.checkQueue(queue);
|
|
349
309
|
}
|
|
350
|
-
async deleteQueue(queue) {
|
|
310
|
+
async deleteQueue(queue, connectionPurpose) {
|
|
351
311
|
RabbitMq.validateName('queue', queue);
|
|
352
|
-
const channel = await this.assertChannel();
|
|
312
|
+
const channel = await this.assertChannel({ connectionPurpose });
|
|
353
313
|
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
354
314
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
355
315
|
debug('queue deleted', deleteQueueRes);
|
|
356
316
|
return deleteQueueRes;
|
|
357
317
|
}
|
|
358
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
359
318
|
async bindQueue(queue, exchange) {
|
|
360
|
-
const channel = await this.
|
|
319
|
+
const channel = await this.assertChannel({ connectionPurpose: consts_1.ConnectionPurpose.Publish });
|
|
361
320
|
await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
362
321
|
return channel.bindQueue(queue, exchange, '');
|
|
363
322
|
}
|
|
364
323
|
async setupQueue(queueName, options) {
|
|
365
324
|
let queue;
|
|
325
|
+
const connectionPurpose = consts_1.ConnectionPurpose.Publish;
|
|
326
|
+
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
366
327
|
const localeOptions = {
|
|
367
328
|
...options,
|
|
368
329
|
durable: true,
|
|
369
330
|
arguments: {
|
|
370
331
|
...options?.arguments,
|
|
371
332
|
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
372
|
-
'x-queue-type': 'quorum',
|
|
333
|
+
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
373
334
|
},
|
|
374
335
|
};
|
|
375
336
|
try {
|
|
376
|
-
const channel = await this.assertChannel();
|
|
337
|
+
const channel = await this.assertChannel({ connectionPurpose });
|
|
377
338
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
378
|
-
await channel.addSetup(
|
|
379
|
-
await setupChannel.assertQueue(queueName, localeOptions);
|
|
380
|
-
});
|
|
339
|
+
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
381
340
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
382
341
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
383
342
|
}
|
|
@@ -385,8 +344,8 @@ class RabbitMq {
|
|
|
385
344
|
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
386
345
|
if (!this.options?.dontRetryAssert) {
|
|
387
346
|
debug('retrying assertQueue', { queueName });
|
|
388
|
-
const channel = await this.assertChannel({ force: true });
|
|
389
|
-
await this.deleteQueue(queueName);
|
|
347
|
+
const channel = await this.assertChannel({ force: true, connectionPurpose });
|
|
348
|
+
await this.deleteQueue(queueName, connectionPurpose);
|
|
390
349
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
391
350
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
392
351
|
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
@@ -399,7 +358,6 @@ class RabbitMq {
|
|
|
399
358
|
this.queues[queueName] = queue;
|
|
400
359
|
return queue;
|
|
401
360
|
}
|
|
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
361
|
static shouldUseQuorum(queueName) {
|
|
404
362
|
const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
|
|
405
363
|
if (envQuorumQueuesWhitelist === '*') {
|
|
@@ -412,6 +370,7 @@ class RabbitMq {
|
|
|
412
370
|
return false;
|
|
413
371
|
}
|
|
414
372
|
async assertQueue(queueName, options) {
|
|
373
|
+
debug('rabbit: start assert queue', { queueName });
|
|
415
374
|
RabbitMq.validateName('queue', queueName);
|
|
416
375
|
if (this.queues[queueName]) {
|
|
417
376
|
delete this.queueSetupPromises[queueName];
|
|
@@ -421,6 +380,7 @@ class RabbitMq {
|
|
|
421
380
|
return this.queueSetupPromises[queueName];
|
|
422
381
|
}
|
|
423
382
|
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
383
|
+
debug('rabbit: done assert queue', { queueName });
|
|
424
384
|
return this.queueSetupPromises[queueName];
|
|
425
385
|
}
|
|
426
386
|
saveConsumer(queue, callback, options) {
|
|
@@ -434,23 +394,9 @@ class RabbitMq {
|
|
|
434
394
|
});
|
|
435
395
|
}
|
|
436
396
|
}
|
|
437
|
-
// Used by the microservices to consume messages from the queue
|
|
438
397
|
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
398
|
await this.consumeFromRabbit(queue, callback, options);
|
|
449
399
|
}
|
|
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
400
|
async lockRedisIfNeeded(msg, options) {
|
|
455
401
|
const { properties: { headers } } = msg;
|
|
456
402
|
const timestamp = headers?.creationTimestamp;
|
|
@@ -473,22 +419,21 @@ class RabbitMq {
|
|
|
473
419
|
const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
|
|
474
420
|
if (useConsumeWithLock) {
|
|
475
421
|
if (!this.redisLock) {
|
|
476
|
-
throw new
|
|
422
|
+
throw new Error('Usage of consumeWithLock requires RedisInstance');
|
|
477
423
|
}
|
|
478
424
|
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
479
425
|
}
|
|
480
|
-
const channel = await this.getNewChannel({});
|
|
426
|
+
const channel = await this.getNewChannel({ connectionPurpose: consts_1.ConnectionPurpose.Consume });
|
|
481
427
|
return channel.addSetup(async (confirmChannel) => {
|
|
482
|
-
logger_1.default.info(`rabbit: channel.addSetup before ${queue} assertQueueOld`);
|
|
483
428
|
const q = await this.assertQueue(queue, optionsWithDefaults);
|
|
484
429
|
await confirmChannel.prefetch(limit, false);
|
|
485
430
|
const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
|
|
486
431
|
if (!msg) {
|
|
487
432
|
return null;
|
|
488
433
|
}
|
|
489
|
-
const traceId = msg.properties.headers
|
|
490
|
-
const userId = msg.properties.headers
|
|
491
|
-
const automationId = msg.properties.headers
|
|
434
|
+
const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
|
|
435
|
+
const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
|
|
436
|
+
const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
|
|
492
437
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
493
438
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
494
439
|
const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
|
|
@@ -556,57 +501,36 @@ class RabbitMq {
|
|
|
556
501
|
}
|
|
557
502
|
});
|
|
558
503
|
}
|
|
559
|
-
// Used by the microservices to consume messages from the exchange
|
|
560
504
|
async consumeFromExchange(queue, exchange, callback, options) {
|
|
561
505
|
const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
|
|
562
506
|
RabbitMq.validateName('exchange', exchange);
|
|
563
507
|
RabbitMq.validateName('queue', queue);
|
|
564
508
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
await this.saveConsumer(queue, callback, options);
|
|
569
|
-
const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
570
|
-
await channel.addSetup(async (c) => {
|
|
571
|
-
const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
|
|
572
|
-
await c.assertQueue(queue);
|
|
573
|
-
this.exchanges[exchange] = assertExchange;
|
|
574
|
-
await c.prefetch(limit, false);
|
|
575
|
-
return Promise.all([
|
|
576
|
-
c.bindQueue(queue, exchange, ''),
|
|
577
|
-
this.consumeNew(queue, callback, options),
|
|
578
|
-
]);
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
// TODO: [QUORUM-PHASE-3] Delete the old implementation
|
|
582
|
-
await this.saveConsumerOld(queue, callback, options);
|
|
583
|
-
const channelOld = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
|
|
584
|
-
await channelOld.addSetup(async (c) => {
|
|
509
|
+
await this.saveConsumer(queue, callback, options);
|
|
510
|
+
const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
511
|
+
return channel.addSetup(async (c) => {
|
|
585
512
|
const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
|
|
586
|
-
|
|
587
|
-
this.
|
|
513
|
+
await c.assertQueue(queue);
|
|
514
|
+
this.exchanges[exchange] = assertExchange;
|
|
588
515
|
await c.prefetch(limit, false);
|
|
589
516
|
return Promise.all([
|
|
590
|
-
|
|
591
|
-
this.
|
|
517
|
+
c.bindQueue(queue, exchange, ''),
|
|
518
|
+
this.consume(queue, callback, options),
|
|
592
519
|
]);
|
|
593
520
|
});
|
|
594
521
|
}
|
|
595
|
-
// Used by the microservices to publish messages to the exchange
|
|
596
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
597
522
|
async publish(exchange, content, customHeaders) {
|
|
523
|
+
debug('rabbit: start publish msg');
|
|
598
524
|
return (0, utils_1.wrapSetImmediate)(async () => {
|
|
599
525
|
RabbitMq.validateName('exchange', exchange);
|
|
600
|
-
const channel = await this.
|
|
601
|
-
await this.
|
|
526
|
+
const channel = await this.assertChannel({ connectionPurpose: consts_1.ConnectionPurpose.Publish });
|
|
527
|
+
await this.assertExchange(exchange, { connectionPurpose: consts_1.ConnectionPurpose.Publish });
|
|
602
528
|
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
603
529
|
});
|
|
604
530
|
}
|
|
605
|
-
// Used by the microservices to send messages to the queue
|
|
606
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
607
531
|
async sendToQueue(queue, content, options, customHeaders) {
|
|
608
532
|
try {
|
|
609
|
-
await this.
|
|
533
|
+
await this.assertChannel({ connectionPurpose: consts_1.ConnectionPurpose.Publish });
|
|
610
534
|
}
|
|
611
535
|
catch (e) {
|
|
612
536
|
logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
@@ -614,55 +538,56 @@ class RabbitMq {
|
|
|
614
538
|
}
|
|
615
539
|
try {
|
|
616
540
|
RabbitMq.validateName('queue', queue);
|
|
617
|
-
await this.
|
|
541
|
+
await this.assertQueue(queue, options);
|
|
618
542
|
}
|
|
619
543
|
catch (e) {
|
|
620
544
|
logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
621
545
|
throw e;
|
|
622
546
|
}
|
|
623
547
|
try {
|
|
624
|
-
const res = await this.
|
|
548
|
+
const res = await this.publishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
625
549
|
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
626
550
|
return res;
|
|
627
551
|
}
|
|
628
552
|
catch (e) {
|
|
629
|
-
|
|
630
|
-
logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
553
|
+
logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}`, { e });
|
|
631
554
|
throw e;
|
|
632
555
|
}
|
|
633
556
|
}
|
|
634
|
-
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
635
557
|
async isConnected() {
|
|
636
|
-
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
558
|
+
debug('rabbit: start is connected');
|
|
559
|
+
const isEachConnectionConnected = await Promise.all(Object.entries(this.connectionsMap).map(async ([connectionPurpose, connectionData]) => {
|
|
560
|
+
const { connection } = connectionData;
|
|
561
|
+
const isConnected = connection?.isConnected();
|
|
562
|
+
if (!isConnected) {
|
|
563
|
+
logger_1.default.error('rabbit: isConnected - false', { connectionPurpose });
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
logger_1.default.info('rabbit: isConnected - true', { connectionPurpose });
|
|
567
|
+
if (connectionPurpose === consts_1.ConnectionPurpose.Publish) {
|
|
568
|
+
const channel = await this.assertChannel({ connectionPurpose: connectionPurpose });
|
|
569
|
+
try {
|
|
570
|
+
await Promise.all([
|
|
571
|
+
channel.waitForConnect(),
|
|
572
|
+
...this.consumers.map((c) => channel.checkQueue(c.queue)),
|
|
573
|
+
]);
|
|
574
|
+
}
|
|
575
|
+
catch (e) {
|
|
576
|
+
logger_1.default.error('rabbit: isConnected - false');
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return true;
|
|
581
|
+
}));
|
|
582
|
+
return isEachConnectionConnected.every((isConnected) => isConnected === true);
|
|
655
583
|
}
|
|
656
584
|
async gracefulShutdown(signal) {
|
|
657
|
-
|
|
658
|
-
const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
|
|
585
|
+
const tagsNumber = this.consumersTags.length;
|
|
659
586
|
logger_1.default.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
660
587
|
const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
661
|
-
const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
662
588
|
// Clean the array to avoid race
|
|
663
589
|
this.consumersTags = [];
|
|
664
|
-
|
|
665
|
-
const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
|
|
590
|
+
const results = await Promise.allSettled(cancelTagPromises);
|
|
666
591
|
const rejected = results.filter((p) => p.status === 'rejected');
|
|
667
592
|
if (rejected.length > 0) {
|
|
668
593
|
logger_1.default.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
|
|
@@ -671,305 +596,6 @@ class RabbitMq {
|
|
|
671
596
|
logger_1.default.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
|
|
672
597
|
}
|
|
673
598
|
}
|
|
674
|
-
async consumeFromRabbitOld(queue, callback, options) {
|
|
675
|
-
const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
|
|
676
|
-
RabbitMq.validateName('queue', queue);
|
|
677
|
-
this.saveConsumerOld(queue, callback, options);
|
|
678
|
-
const uniqueId = (0, node_crypto_1.randomUUID)();
|
|
679
|
-
const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
|
|
680
|
-
if (useConsumeWithLock) {
|
|
681
|
-
if (!this.redisLock) {
|
|
682
|
-
throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
|
|
683
|
-
}
|
|
684
|
-
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
685
|
-
}
|
|
686
|
-
const channel = await this.getNewChannelOld({});
|
|
687
|
-
return channel.addSetup(async (confirmChannel) => {
|
|
688
|
-
const q = await this.assertQueueOld(queue, optionsWithDefaults);
|
|
689
|
-
await confirmChannel.prefetch(limit, false);
|
|
690
|
-
const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
|
|
691
|
-
if (!msg) {
|
|
692
|
-
return null;
|
|
693
|
-
}
|
|
694
|
-
const traceId = msg.properties.headers?.[consts_1.TRACING_HEADER];
|
|
695
|
-
const userId = msg.properties.headers?.[consts_1.USER_TRACING_HEADER];
|
|
696
|
-
const automationId = msg.properties.headers?.[consts_1.AUTOMATION_ID_HEADER];
|
|
697
|
-
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
698
|
-
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
699
|
-
const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
|
|
700
|
-
// setting also outbreak trace as part of legacy code
|
|
701
|
-
const outbreakTrace = zehut_1.outbreak.newTrace(zehut_1.traceTypes.RABBIT);
|
|
702
|
-
// enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
|
|
703
|
-
// and we don't want to fail the flow because of it
|
|
704
|
-
if (userId && enableRabbitTrace) {
|
|
705
|
-
try {
|
|
706
|
-
await Promise.all([
|
|
707
|
-
(0, zehut_1.createOrSetRabbitTrace)(trace, userId),
|
|
708
|
-
(0, zehut_1.createOrSetRabbitTrace)(outbreakTrace, userId),
|
|
709
|
-
]);
|
|
710
|
-
}
|
|
711
|
-
catch (e) {
|
|
712
|
-
logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
713
|
-
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
if (traceId) {
|
|
717
|
-
trace?.context?.set(consts_1.TRACING_HEADER, traceId);
|
|
718
|
-
outbreakTrace?.context.set(consts_1.TRACING_HEADER, traceId);
|
|
719
|
-
}
|
|
720
|
-
if (auditContext) {
|
|
721
|
-
await auditContext(queue, {
|
|
722
|
-
userId,
|
|
723
|
-
automationId,
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
727
|
-
if (!shouldConsume) {
|
|
728
|
-
await this.unlockRedisIfNeeded(releaseLock);
|
|
729
|
-
return this.ack(confirmChannel, msg)(msg);
|
|
730
|
-
}
|
|
731
|
-
let messageAcked = false;
|
|
732
|
-
// setting the localAck function to be used in the callback
|
|
733
|
-
const localAck = async () => {
|
|
734
|
-
if (messageAcked) {
|
|
735
|
-
return;
|
|
736
|
-
}
|
|
737
|
-
messageAcked = true;
|
|
738
|
-
return this.ack(confirmChannel, msg, true, releaseLock)(msg);
|
|
739
|
-
};
|
|
740
|
-
const localNack = async (_, nackOptions = {}) => {
|
|
741
|
-
if (messageAcked) {
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
745
|
-
messageAcked = true;
|
|
746
|
-
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
|
|
747
|
-
};
|
|
748
|
-
try {
|
|
749
|
-
await callback(parsedMessage, localAck, localNack);
|
|
750
|
-
}
|
|
751
|
-
catch (e) {
|
|
752
|
-
await localNack(msg);
|
|
753
|
-
}
|
|
754
|
-
}, types_1.CONSUMER_DEFAULT_OPTIONS);
|
|
755
|
-
if (!consumerTag) {
|
|
756
|
-
logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
|
|
757
|
-
}
|
|
758
|
-
else {
|
|
759
|
-
logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
760
|
-
this.oldConsumersTags.push([confirmChannel, consumerTag]);
|
|
761
|
-
}
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
// TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
|
|
765
|
-
async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
|
|
766
|
-
let connection;
|
|
767
|
-
try {
|
|
768
|
-
connection = await this.getConnectionOld();
|
|
769
|
-
}
|
|
770
|
-
catch (e) {
|
|
771
|
-
logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
772
|
-
throw e;
|
|
773
|
-
}
|
|
774
|
-
const channel = connection.createChannel({ ...options });
|
|
775
|
-
(0, events_1.once)(channel, 'close').then((args) => {
|
|
776
|
-
logger_1.default.error(`rabbit: channel ${name} closed`);
|
|
777
|
-
onClose?.(args);
|
|
778
|
-
});
|
|
779
|
-
try {
|
|
780
|
-
await (0, events_1.once)(channel, 'connect');
|
|
781
|
-
debug(`rabbit: channel ${name} CONNECTED`);
|
|
782
|
-
return channel;
|
|
783
|
-
}
|
|
784
|
-
catch (err) {
|
|
785
|
-
logger_1.default.error(`rabbit: channel error ${name} error`, { err });
|
|
786
|
-
throw err;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
async getConnectionOld() {
|
|
790
|
-
return new Promise(async (resolve, reject) => {
|
|
791
|
-
if (this.oldBlockReconnect) {
|
|
792
|
-
debug('rabbit: block reconnect');
|
|
793
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
794
|
-
// @ts-ignore
|
|
795
|
-
return resolve();
|
|
796
|
-
}
|
|
797
|
-
if (this.oldConnection !== null) {
|
|
798
|
-
if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
|
|
799
|
-
debug('rabbit: connection - is connected');
|
|
800
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
801
|
-
// @ts-ignore
|
|
802
|
-
return resolve(this.oldConnection);
|
|
803
|
-
}
|
|
804
|
-
debug('rabbit: connection - reconnecting');
|
|
805
|
-
}
|
|
806
|
-
if (this.oldCreatingConnection) {
|
|
807
|
-
debug('rabbit: creating connection emi');
|
|
808
|
-
this.oldEm.once(consts_1.CONNECTION_CREATED_CONST, resolve);
|
|
809
|
-
this.oldEm.once(consts_1.CONNECTION_FAILED_CONST, reject);
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
this.oldCreatingConnection = true;
|
|
813
|
-
let isResolved = false;
|
|
814
|
-
// It is import to use it as a function and not as a variable
|
|
815
|
-
// because of k8s changes the env variables
|
|
816
|
-
// and we want to use the new values
|
|
817
|
-
const findServers = () => {
|
|
818
|
-
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
819
|
-
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
820
|
-
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
821
|
-
debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
822
|
-
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
823
|
-
};
|
|
824
|
-
const defaultUrls = findServers();
|
|
825
|
-
const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
|
|
826
|
-
findServers,
|
|
827
|
-
});
|
|
828
|
-
this.oldConnection = connection;
|
|
829
|
-
this.oldConnection.on('error', (err) => {
|
|
830
|
-
logger_1.default.error('rabbit: connection error', { err });
|
|
831
|
-
if (!isResolved) {
|
|
832
|
-
isResolved = true;
|
|
833
|
-
reject(err);
|
|
834
|
-
this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
835
|
-
}
|
|
836
|
-
});
|
|
837
|
-
this.oldConnection.on('connectFailed', (err) => {
|
|
838
|
-
this.oldConsumersTags = [];
|
|
839
|
-
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
840
|
-
if (!isResolved) {
|
|
841
|
-
isResolved = true;
|
|
842
|
-
reject(err);
|
|
843
|
-
this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
844
|
-
}
|
|
845
|
-
});
|
|
846
|
-
this.oldConnection.on('disconnect', ({ err }) => {
|
|
847
|
-
this.oldConsumersTags = [];
|
|
848
|
-
debug('rabbit: connection closed');
|
|
849
|
-
if (this.options?.disableReconnect) {
|
|
850
|
-
logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
851
|
-
this.oldBlockReconnect = true;
|
|
852
|
-
}
|
|
853
|
-
else {
|
|
854
|
-
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
855
|
-
}
|
|
856
|
-
});
|
|
857
|
-
this.oldConnection.once('connect', async () => {
|
|
858
|
-
debug('rabbit: connection established');
|
|
859
|
-
this.oldCreatingConnection = false;
|
|
860
|
-
this.oldEm.emit(consts_1.CONNECTION_CREATED_CONST, connection);
|
|
861
|
-
isResolved = true;
|
|
862
|
-
resolve(connection);
|
|
863
|
-
});
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
saveConsumerOld(queue, callback, options) {
|
|
867
|
-
const isConsumerExist = this.oldConsumers.some((consumer) => consumer.queue === queue);
|
|
868
|
-
if (!isConsumerExist) {
|
|
869
|
-
logger_1.default.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
870
|
-
this.oldConsumers.push({
|
|
871
|
-
queue,
|
|
872
|
-
callback,
|
|
873
|
-
options,
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
async assertQueueOld(queueName, options) {
|
|
878
|
-
RabbitMq.validateName('queue', queueName);
|
|
879
|
-
if (this.oldQueues[queueName]) {
|
|
880
|
-
delete this.oldQueueSetupPromises[queueName];
|
|
881
|
-
return this.oldQueues[queueName];
|
|
882
|
-
}
|
|
883
|
-
if (this.oldQueueSetupPromises[queueName]) {
|
|
884
|
-
return this.oldQueueSetupPromises[queueName];
|
|
885
|
-
}
|
|
886
|
-
this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
|
|
887
|
-
return this.oldQueueSetupPromises[queueName];
|
|
888
|
-
}
|
|
889
|
-
async setupQueueOld(queueName, options) {
|
|
890
|
-
// let queue: Replies.AssertQueue;
|
|
891
|
-
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
892
|
-
const localeOptions = {
|
|
893
|
-
...options,
|
|
894
|
-
durable: true,
|
|
895
|
-
arguments: {
|
|
896
|
-
...options?.arguments,
|
|
897
|
-
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
898
|
-
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
899
|
-
},
|
|
900
|
-
};
|
|
901
|
-
try {
|
|
902
|
-
const channel = await this.assertChannelOld();
|
|
903
|
-
debug('assertQueue->channel.addSetup', { queueName });
|
|
904
|
-
// await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
905
|
-
debug('assertQueue->channel.assertQueue', { queueName });
|
|
906
|
-
// queue = await channel.assertQueue(queueName, localeOptions);
|
|
907
|
-
}
|
|
908
|
-
catch (e) {
|
|
909
|
-
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
910
|
-
if (!this.options?.dontRetryAssert) {
|
|
911
|
-
debug('retrying assertQueue', { queueName });
|
|
912
|
-
const channel = await this.assertChannelOld({ force: true });
|
|
913
|
-
await this.deleteQueueOld(queueName);
|
|
914
|
-
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
915
|
-
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
916
|
-
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
917
|
-
// queue = await channel.assertQueue(queueName, localeOptions);
|
|
918
|
-
}
|
|
919
|
-
else {
|
|
920
|
-
throw e;
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
const queue = {
|
|
924
|
-
queue: 'bla bla queue',
|
|
925
|
-
messageCount: 0,
|
|
926
|
-
consumerCount: 2,
|
|
927
|
-
};
|
|
928
|
-
this.oldQueues[queueName] = queue;
|
|
929
|
-
return queue;
|
|
930
|
-
}
|
|
931
|
-
async assertChannelOld({ force = false } = {}) {
|
|
932
|
-
if (!this.oldPublishChannelSetupPromise) {
|
|
933
|
-
this.oldPublishChannelSetupPromise = new Promise(async (resolve, reject) => {
|
|
934
|
-
if (this.oldChannel && !force) {
|
|
935
|
-
return resolve(this.oldChannel);
|
|
936
|
-
}
|
|
937
|
-
try {
|
|
938
|
-
const channel = await this.getNewChannelOld({});
|
|
939
|
-
channel.on('error', (err) => {
|
|
940
|
-
logger_1.default.error('rabbit: channel error', { err });
|
|
941
|
-
});
|
|
942
|
-
this.oldChannel = channel;
|
|
943
|
-
resolve(channel);
|
|
944
|
-
}
|
|
945
|
-
catch (e) {
|
|
946
|
-
reject(e);
|
|
947
|
-
}
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
return this.oldPublishChannelSetupPromise;
|
|
951
|
-
}
|
|
952
|
-
async deleteQueueOld(queue) {
|
|
953
|
-
RabbitMq.validateName('queue', queue);
|
|
954
|
-
const channel = await this.assertChannelOld();
|
|
955
|
-
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
956
|
-
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
957
|
-
debug('queue deleted', deleteQueueRes);
|
|
958
|
-
return deleteQueueRes;
|
|
959
|
-
}
|
|
960
|
-
async assertExchangeOld(exchangeName, options) {
|
|
961
|
-
const channel = await this.assertChannelOld();
|
|
962
|
-
if (this.oldExchanges[exchangeName]) {
|
|
963
|
-
delete this.oldAssertExchangePromises[exchangeName];
|
|
964
|
-
return this.oldExchanges[exchangeName];
|
|
965
|
-
}
|
|
966
|
-
if (this.oldAssertExchangePromises[exchangeName]) {
|
|
967
|
-
return this.oldAssertExchangePromises[exchangeName];
|
|
968
|
-
}
|
|
969
|
-
this.oldAssertExchangePromises[exchangeName] = (0, utils_1.assertExchangeFanout)(channel, exchangeName);
|
|
970
|
-
this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
|
|
971
|
-
return this.oldExchanges[exchangeName];
|
|
972
|
-
}
|
|
973
599
|
}
|
|
974
600
|
exports.default = RabbitMq;
|
|
975
601
|
var celery_1 = require("./lib/celery");
|