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