@autofleet/rabbit 3.3.2 → 3.3.22-connection-test-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +1 -1
- package/dist/index.d.ts +1 -29
- package/dist/index.js +97 -458
- package/dist/lib/consts.js +0 -1
- package/dist/lib/rabbitError.js +0 -1
- package/dist/lib/redis.js +0 -1
- package/dist/lib/types.d.ts +0 -1
- 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 +17 -27
- package/src/index.ts +115 -538
- package/src/lib/types.ts +0 -2
- package/src/{mock/index.ts → mock.ts} +2 -2
- package/tsconfig.json +2 -2
- package/dist/index.js.map +0 -1
- package/dist/lib/celery.d.ts +0 -9
- package/dist/lib/celery.js +0 -55
- 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/lib/celery.ts +0 -89
- package/src/mock/vitest.ts +0 -24
- package/tsconfig.build.json +0 -5
- package/vitest.config.ts +0 -16
package/src/index.ts
CHANGED
|
@@ -100,6 +100,44 @@ type AfConsumer = {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
const HEARTBEAT = '60';
|
|
103
|
+
const withTimeout = async<T>(promise: Promise<T>, timeoutMs: number): Promise<T> => new Promise((resolve, reject) => {
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
reject(new Error(`Promise timed out after ${timeoutMs} ms`));
|
|
106
|
+
}, timeoutMs);
|
|
107
|
+
|
|
108
|
+
promise
|
|
109
|
+
.then((value) => {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
resolve(value);
|
|
112
|
+
})
|
|
113
|
+
.catch((err) => {
|
|
114
|
+
clearTimeout(timer);
|
|
115
|
+
reject(err);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const withRetry = async <T>(
|
|
120
|
+
operation: () => Promise<T>,
|
|
121
|
+
retries: number,
|
|
122
|
+
timeoutMs: number,
|
|
123
|
+
): Promise<T> => new Promise(async (resolve, reject) => {
|
|
124
|
+
let lastError: any;
|
|
125
|
+
|
|
126
|
+
for (let attempt = 1; attempt <= retries; attempt += 1) {
|
|
127
|
+
try {
|
|
128
|
+
// eslint-disable-next-line no-await-in-loop
|
|
129
|
+
const result = await withTimeout(operation(), timeoutMs);
|
|
130
|
+
return resolve(result);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
lastError = err;
|
|
133
|
+
logger.error(`Attempt ${attempt} failed: ${err}`);
|
|
134
|
+
if (attempt < retries) {
|
|
135
|
+
logger.info(`Retrying (${attempt}/${retries})...`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
reject(lastError);
|
|
140
|
+
});
|
|
103
141
|
|
|
104
142
|
class RabbitMq implements IAfRabbitMq {
|
|
105
143
|
static parseMsg(msg: any) : any {
|
|
@@ -174,36 +212,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
174
212
|
|
|
175
213
|
private consumers: Array<AfConsumer> = [];
|
|
176
214
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
private vhost = 'quorum-vhost';
|
|
180
|
-
|
|
181
|
-
// TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
|
|
182
|
-
oldChannel: ChannelWrapper | null;
|
|
183
|
-
|
|
184
|
-
oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
185
|
-
|
|
186
|
-
oldBlockReconnect: boolean | null | undefined
|
|
187
|
-
|
|
188
|
-
oldConnection: AmqpConnectionManager | null | undefined
|
|
189
|
-
|
|
190
|
-
oldEm: EventEmitter;
|
|
191
|
-
|
|
192
|
-
oldCreatingConnection: boolean;
|
|
193
|
-
|
|
194
|
-
oldExchanges: ExchangesCache;
|
|
195
|
-
|
|
196
|
-
oldQueues: QueuesCache;
|
|
197
|
-
|
|
198
|
-
oldQueueSetupPromises: QueueSetupPromisesDictionary;
|
|
199
|
-
|
|
200
|
-
oldAssertExchangePromises: AssertExchangePromisesDictionary;
|
|
201
|
-
|
|
202
|
-
oldConsumersTags: Array<[ConfirmChannel, string]>;
|
|
203
|
-
|
|
204
|
-
private oldConsumers: Array<AfConsumer> = [];
|
|
205
|
-
|
|
206
|
-
constructor(options: AfRabbitOptions = {}, redisConfig?: RedisConfig) {
|
|
215
|
+
constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig) {
|
|
207
216
|
this.em = new EventEmitter();
|
|
208
217
|
this.channel = null;
|
|
209
218
|
this.publishChannelSetupPromise = null;
|
|
@@ -215,7 +224,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
215
224
|
this.assertExchangePromises = {};
|
|
216
225
|
this.consumers = [];
|
|
217
226
|
this.options = options;
|
|
218
|
-
|
|
219
227
|
this.redisClient = redisConfig && getRedisInstance(redisConfig);
|
|
220
228
|
if (this.redisClient) {
|
|
221
229
|
this.redisLock = promisify(RedisLock(this.redisClient)) as RedisLockType;
|
|
@@ -230,74 +238,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
230
238
|
await this.gracefulShutdown('SIGINT');
|
|
231
239
|
});
|
|
232
240
|
}
|
|
233
|
-
|
|
234
|
-
// TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
|
|
235
|
-
this.oldEm = new EventEmitter();
|
|
236
|
-
this.oldChannel = null;
|
|
237
|
-
this.oldPublishChannelSetupPromise = null;
|
|
238
|
-
this.oldConnection = null;
|
|
239
|
-
this.oldCreatingConnection = false;
|
|
240
|
-
this.oldExchanges = {};
|
|
241
|
-
this.oldQueues = {};
|
|
242
|
-
this.oldQueueSetupPromises = {};
|
|
243
|
-
this.oldAssertExchangePromises = {};
|
|
244
|
-
this.oldConsumers = [];
|
|
245
|
-
this.oldConsumersTags = [];
|
|
246
241
|
}
|
|
247
242
|
|
|
248
|
-
private assertVHost = async () => {
|
|
249
|
-
if (this.doesVHostExist) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const username = process.env.RABBITMQ_USERNAME || 'guest';
|
|
254
|
-
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
255
|
-
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
|
|
256
|
-
const headers = {
|
|
257
|
-
Authorization: `Basic ${credentials}`,
|
|
258
|
-
'Content-Type': 'application/json',
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
|
|
262
|
-
|
|
263
|
-
const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
const response = await fetch(url, {
|
|
267
|
-
method: 'GET',
|
|
268
|
-
headers,
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
if (response.status === 200) {
|
|
272
|
-
this.doesVHostExist = true;
|
|
273
|
-
logger.info('Vhost exists', { vhost: this.vhost });
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (response.status !== 404) {
|
|
278
|
-
logger.error('Failed to check vhost', { response });
|
|
279
|
-
throw new RabbitError('Failed to check vhost');
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const createResponse = await fetch(url, {
|
|
283
|
-
method: 'PUT',
|
|
284
|
-
headers,
|
|
285
|
-
body: JSON.stringify({ default_queue_type: 'quorum' }),
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
if (!createResponse.ok) {
|
|
289
|
-
logger.error('Failed to create vhost', { response: createResponse });
|
|
290
|
-
throw new RabbitError('Failed to create vhost');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
this.doesVHostExist = true;
|
|
294
|
-
logger.info('Vhost created', { vhost: this.vhost });
|
|
295
|
-
} catch (error) {
|
|
296
|
-
logger.error('Failed to check or create vhost', { error });
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
|
|
301
243
|
private shouldConsumeMessageByTimestamp = async (msg: ConsumeMessageOrNull) => {
|
|
302
244
|
if (msg) {
|
|
303
245
|
const { properties: { headers } } = msg;
|
|
@@ -345,13 +287,13 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
345
287
|
if (
|
|
346
288
|
!skipRetry
|
|
347
289
|
&& (
|
|
348
|
-
!msg.properties.headers
|
|
290
|
+
!msg.properties.headers[RETRY_HEADER]
|
|
349
291
|
|| parseInt(msg.properties.headers[RETRY_HEADER], 10) < options.retries
|
|
350
292
|
)
|
|
351
293
|
) {
|
|
352
294
|
await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
|
|
353
295
|
...msg.properties.headers,
|
|
354
|
-
[RETRY_HEADER]: msg.properties.headers
|
|
296
|
+
[RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
|
|
355
297
|
? msg.properties.headers[RETRY_HEADER] + 1
|
|
356
298
|
: 1,
|
|
357
299
|
});
|
|
@@ -359,7 +301,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
359
301
|
const deadQueue = `${queue}-dead`;
|
|
360
302
|
await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
|
|
361
303
|
...msg.properties.headers,
|
|
362
|
-
[RETRY_HEADER]: msg.properties.headers
|
|
304
|
+
[RETRY_HEADER]: msg.properties.headers[RETRY_HEADER]
|
|
363
305
|
? msg.properties.headers[RETRY_HEADER] + 1
|
|
364
306
|
: 1,
|
|
365
307
|
});
|
|
@@ -408,7 +350,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
408
350
|
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
409
351
|
|
|
410
352
|
debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
411
|
-
|
|
353
|
+
|
|
354
|
+
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
412
355
|
};
|
|
413
356
|
|
|
414
357
|
const defaultUrls = findServers();
|
|
@@ -428,10 +371,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
428
371
|
|
|
429
372
|
this.connection.on('connectFailed', (err) => {
|
|
430
373
|
this.consumersTags = [];
|
|
431
|
-
|
|
432
|
-
err.url = this.maskURL(err.url);
|
|
433
|
-
}
|
|
434
|
-
logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
|
|
374
|
+
logger.error('rabbit: connection connectFailed', { err });
|
|
435
375
|
if (!isResolved) {
|
|
436
376
|
isResolved = true;
|
|
437
377
|
reject(err);
|
|
@@ -523,12 +463,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
523
463
|
return this.exchanges[exchangeName];
|
|
524
464
|
}
|
|
525
465
|
|
|
526
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
527
466
|
async getQueueLength(queue: string) {
|
|
528
467
|
RabbitMq.validateName('queue', queue);
|
|
529
|
-
const {
|
|
468
|
+
const { channel } = this;
|
|
530
469
|
if (!channel) {
|
|
531
|
-
throw new
|
|
470
|
+
throw new Error('channel is not defined');
|
|
532
471
|
}
|
|
533
472
|
debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
|
|
534
473
|
return channel?.checkQueue(queue);
|
|
@@ -543,30 +482,28 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
543
482
|
return deleteQueueRes;
|
|
544
483
|
}
|
|
545
484
|
|
|
546
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
547
485
|
async bindQueue(queue: string, exchange: string) {
|
|
548
|
-
const channel: ChannelWrapper = await this.
|
|
486
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
549
487
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
550
488
|
return channel.bindQueue(queue, exchange, '');
|
|
551
489
|
}
|
|
552
490
|
|
|
553
491
|
async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
554
492
|
let queue: Replies.AssertQueue;
|
|
493
|
+
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
555
494
|
const localeOptions = {
|
|
556
495
|
...options,
|
|
557
496
|
durable: true,
|
|
558
497
|
arguments: {
|
|
559
498
|
...options?.arguments,
|
|
560
499
|
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
561
|
-
'x-queue-type': 'quorum',
|
|
500
|
+
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
562
501
|
},
|
|
563
502
|
};
|
|
564
503
|
try {
|
|
565
504
|
const channel: ChannelWrapper = await this.assertChannel();
|
|
566
505
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
567
|
-
await channel.addSetup(
|
|
568
|
-
await setupChannel.assertQueue(queueName, localeOptions);
|
|
569
|
-
});
|
|
506
|
+
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
570
507
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
571
508
|
queue = await channel.assertQueue(queueName, localeOptions);
|
|
572
509
|
} catch (e) {
|
|
@@ -589,7 +526,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
589
526
|
return queue;
|
|
590
527
|
}
|
|
591
528
|
|
|
592
|
-
// TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
|
|
593
529
|
static shouldUseQuorum(queueName: string): boolean {
|
|
594
530
|
const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
|
|
595
531
|
|
|
@@ -632,27 +568,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
632
568
|
}
|
|
633
569
|
}
|
|
634
570
|
|
|
635
|
-
// Used by the microservices to consume messages from the queue
|
|
636
571
|
async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
637
|
-
// TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
|
|
638
|
-
if (options?.isQuorumQueue !== false) {
|
|
639
|
-
await this.assertVHost();
|
|
640
|
-
await this.consumeNew(queue, callback, options);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
await this.consumeOld(queue, callback, options);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
|
|
647
|
-
async consumeNew(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
648
572
|
await this.consumeFromRabbit(queue, callback, options);
|
|
649
573
|
}
|
|
650
574
|
|
|
651
|
-
// TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
|
|
652
|
-
async consumeOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
653
|
-
await this.consumeFromRabbitOld(queue, callback, options);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
575
|
private async lockRedisIfNeeded(msg: any, options: any) {
|
|
657
576
|
const { properties: { headers } } = msg;
|
|
658
577
|
const timestamp = headers?.creationTimestamp;
|
|
@@ -683,7 +602,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
683
602
|
} = optionsWithDefaults;
|
|
684
603
|
if (useConsumeWithLock) {
|
|
685
604
|
if (!this.redisLock) {
|
|
686
|
-
throw new
|
|
605
|
+
throw new Error('Usage of consumeWithLock requires RedisInstance');
|
|
687
606
|
}
|
|
688
607
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
689
608
|
}
|
|
@@ -698,9 +617,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
698
617
|
return null;
|
|
699
618
|
}
|
|
700
619
|
|
|
701
|
-
const traceId = msg.properties.headers
|
|
702
|
-
const userId = msg.properties.headers
|
|
703
|
-
const automationId = msg.properties.headers
|
|
620
|
+
const traceId = msg.properties.headers[TRACING_HEADER];
|
|
621
|
+
const userId = msg.properties.headers[USER_TRACING_HEADER];
|
|
622
|
+
const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
|
|
704
623
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
705
624
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
706
625
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -777,45 +696,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
777
696
|
});
|
|
778
697
|
}
|
|
779
698
|
|
|
780
|
-
// Used by the microservices to consume messages from the exchange
|
|
781
699
|
async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
|
|
782
700
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
783
701
|
RabbitMq.validateName('exchange', exchange);
|
|
784
702
|
RabbitMq.validateName('queue', queue);
|
|
785
703
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
await this.assertVHost();
|
|
789
|
-
await this.saveConsumer(queue, callback, options);
|
|
790
|
-
const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
791
|
-
|
|
792
|
-
await channel.addSetup(async (c: ConfirmChannel) => {
|
|
793
|
-
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
794
|
-
await c.assertQueue(queue);
|
|
795
|
-
this.exchanges[exchange] = assertExchange;
|
|
796
|
-
await c.prefetch(limit, false);
|
|
797
|
-
return Promise.all([
|
|
798
|
-
c.bindQueue(queue, exchange, ''),
|
|
799
|
-
this.consumeNew(
|
|
800
|
-
queue,
|
|
801
|
-
callback,
|
|
802
|
-
options,
|
|
803
|
-
),
|
|
804
|
-
]);
|
|
805
|
-
});
|
|
806
|
-
}
|
|
704
|
+
await this.saveConsumer(queue, callback, options);
|
|
705
|
+
const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
807
706
|
|
|
808
|
-
|
|
809
|
-
await this.saveConsumerOld(queue, callback, options);
|
|
810
|
-
const channelOld: ChannelWrapper = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
|
|
811
|
-
await channelOld.addSetup(async (c: ConfirmChannel) => {
|
|
707
|
+
return channel.addSetup(async (c: ConfirmChannel) => {
|
|
812
708
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
813
709
|
await c.assertQueue(queue);
|
|
814
|
-
this.
|
|
815
|
-
await c.prefetch(limit,
|
|
710
|
+
this.exchanges[exchange] = assertExchange;
|
|
711
|
+
await c.prefetch(limit, true);
|
|
816
712
|
return Promise.all([
|
|
817
713
|
c.bindQueue(queue, exchange, ''),
|
|
818
|
-
this.
|
|
714
|
+
this.consume(
|
|
819
715
|
queue,
|
|
820
716
|
callback,
|
|
821
717
|
options,
|
|
@@ -824,21 +720,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
824
720
|
});
|
|
825
721
|
}
|
|
826
722
|
|
|
827
|
-
// Used by the microservices to publish messages to the exchange
|
|
828
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
829
723
|
async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
|
|
830
724
|
return wrapSetImmediate(async () => {
|
|
831
725
|
RabbitMq.validateName('exchange', exchange);
|
|
832
|
-
const channel: ChannelWrapper = await this.
|
|
833
|
-
await this.
|
|
726
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
727
|
+
await this.assertExchange(exchange);
|
|
834
728
|
await channel.publish(exchange, '',
|
|
835
729
|
Buffer.from(JSON.stringify(content)),
|
|
836
730
|
RabbitMq.getPublishOptions(customHeaders));
|
|
837
731
|
});
|
|
838
732
|
}
|
|
839
733
|
|
|
840
|
-
// Used by the microservices to send messages to the queue
|
|
841
|
-
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
842
734
|
async sendToQueue(
|
|
843
735
|
queue: string,
|
|
844
736
|
content: any,
|
|
@@ -846,7 +738,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
846
738
|
customHeaders?: any,
|
|
847
739
|
): Promise<boolean | undefined> {
|
|
848
740
|
try {
|
|
849
|
-
await this.
|
|
741
|
+
await this.assertChannel();
|
|
850
742
|
} catch (e) {
|
|
851
743
|
logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
852
744
|
throw e;
|
|
@@ -854,14 +746,14 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
854
746
|
|
|
855
747
|
try {
|
|
856
748
|
RabbitMq.validateName('queue', queue);
|
|
857
|
-
await this.
|
|
749
|
+
await this.assertQueue(queue, options);
|
|
858
750
|
} catch (e) {
|
|
859
751
|
logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
860
752
|
throw e;
|
|
861
753
|
}
|
|
862
754
|
|
|
863
755
|
try {
|
|
864
|
-
const res = await this.
|
|
756
|
+
const res = await this.channel?.sendToQueue(queue,
|
|
865
757
|
Buffer.from(JSON.stringify(content)),
|
|
866
758
|
RabbitMq.getPublishOptions(customHeaders));
|
|
867
759
|
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
@@ -873,38 +765,67 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
873
765
|
}
|
|
874
766
|
}
|
|
875
767
|
|
|
876
|
-
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
877
768
|
async isConnected() : Promise<boolean> {
|
|
878
|
-
const connection = await this.getConnectionOld();
|
|
879
|
-
const isConnected = connection.isConnected();
|
|
880
|
-
if (!isConnected) {
|
|
881
|
-
logger.error('rabbit: isConnected - false');
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
884
|
-
const channel: any = await this.assertChannelOld();
|
|
885
769
|
try {
|
|
886
|
-
await
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
770
|
+
const connection = await this.getConnection();
|
|
771
|
+
if (!connection.isConnected()) {
|
|
772
|
+
logger.error('rabbit: isConnected - false');
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
const channel: any = await this.assertChannel();
|
|
776
|
+
const timeoutMs = 5000;
|
|
777
|
+
const retries = 2;
|
|
778
|
+
const chunkSize = 10;
|
|
779
|
+
const processChunks = async (consumers: AfConsumer[]): Promise<boolean> => {
|
|
780
|
+
for (let i = 0; i < consumers.length; i += chunkSize) {
|
|
781
|
+
const chunk = consumers.slice(i, i + chunkSize);
|
|
782
|
+
// eslint-disable-next-line no-await-in-loop
|
|
783
|
+
const chunkResults = await Promise.all(
|
|
784
|
+
chunk.map((c: AfConsumer) => withRetry(() => channel.checkQueue(c.queue), retries, timeoutMs).catch((err) => {
|
|
785
|
+
logger.error(`rabbit: Error in isConnected (checkQueue) - ${err.message}`);
|
|
786
|
+
return null;
|
|
787
|
+
})),
|
|
788
|
+
);
|
|
789
|
+
if (chunkResults.some((res) => res === null)) {
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return true;
|
|
794
|
+
};
|
|
795
|
+
const waitForConnectResult = await withRetry(
|
|
796
|
+
() => channel.waitForConnect(),
|
|
797
|
+
retries,
|
|
798
|
+
timeoutMs,
|
|
799
|
+
).catch((err) => {
|
|
800
|
+
logger.error(`rabbit: Error in isConnected (waitForConnect) - ${err.message}`);
|
|
801
|
+
return null;
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
if (waitForConnectResult === null) {
|
|
805
|
+
logger.error('rabbit: isConnected - false due to failed waitForConnect');
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
const allConsumersConnected = await processChunks(this.consumers);
|
|
809
|
+
if (!allConsumersConnected) {
|
|
810
|
+
logger.error('rabbit: isConnected - false due to failed consumer checks');
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
logger.info('rabbit: isConnected - true');
|
|
815
|
+
return true;
|
|
890
816
|
} catch (e) {
|
|
891
|
-
logger.error(
|
|
817
|
+
logger.error(`rabbit: isConnected - Exception occurred: ${e}`);
|
|
892
818
|
return false;
|
|
893
819
|
}
|
|
894
|
-
logger.info('rabbit: isConnected - true');
|
|
895
|
-
return true;
|
|
896
820
|
}
|
|
897
821
|
|
|
898
822
|
async gracefulShutdown(signal: string) : Promise<void> {
|
|
899
|
-
|
|
900
|
-
const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
|
|
823
|
+
const tagsNumber = this.consumersTags.length;
|
|
901
824
|
logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
902
825
|
const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
903
|
-
const cancelTagPromisesOld = this.oldConsumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
904
826
|
// Clean the array to avoid race
|
|
905
827
|
this.consumersTags = [];
|
|
906
|
-
|
|
907
|
-
const results = await Promise.allSettled([...cancelTagPromises, ...cancelTagPromisesOld]);
|
|
828
|
+
const results = await Promise.allSettled(cancelTagPromises);
|
|
908
829
|
const rejected = results.filter((p) => p.status === 'rejected');
|
|
909
830
|
if (rejected.length > 0) {
|
|
910
831
|
logger.warn(`rabbit: [gracefully-shutdown] #${rejected.length}/${tagsNumber} tags failed to cancel: ${rejected}`);
|
|
@@ -912,350 +833,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
912
833
|
logger.info('rabbit: [gracefully-shutdown] all tags successfully canceled.');
|
|
913
834
|
}
|
|
914
835
|
}
|
|
915
|
-
|
|
916
|
-
private async consumeFromRabbitOld(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
917
|
-
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
918
|
-
RabbitMq.validateName('queue', queue);
|
|
919
|
-
this.saveConsumerOld(queue, callback, options);
|
|
920
|
-
const uniqueId = randomUUID();
|
|
921
|
-
const {
|
|
922
|
-
limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace,
|
|
923
|
-
} = optionsWithDefaults;
|
|
924
|
-
if (useConsumeWithLock) {
|
|
925
|
-
if (!this.redisLock) {
|
|
926
|
-
throw new RabbitError('Usage of consumeWithLock requires RedisInstance');
|
|
927
|
-
}
|
|
928
|
-
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
929
|
-
}
|
|
930
|
-
const channel = await this.getNewChannelOld({});
|
|
931
|
-
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
932
|
-
const q = await this.assertQueueOld(queue, optionsWithDefaults);
|
|
933
|
-
await confirmChannel.prefetch(limit, false);
|
|
934
|
-
const { consumerTag } = await confirmChannel.consume(
|
|
935
|
-
queue,
|
|
936
|
-
async (msg: ConsumeMessageOrNull) => {
|
|
937
|
-
if (!msg) {
|
|
938
|
-
return null;
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
const traceId = msg.properties.headers![TRACING_HEADER];
|
|
942
|
-
const userId = msg.properties.headers![USER_TRACING_HEADER];
|
|
943
|
-
const automationId = msg.properties.headers![AUTOMATION_ID_HEADER];
|
|
944
|
-
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
945
|
-
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
946
|
-
const trace = newTrace(traceTypes.RABBIT);
|
|
947
|
-
// setting also outbreak trace as part of legacy code
|
|
948
|
-
const outbreakTrace = outbreak.newTrace(traceTypes.RABBIT);
|
|
949
|
-
// enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
|
|
950
|
-
// and we don't want to fail the flow because of it
|
|
951
|
-
if (userId && enableRabbitTrace) {
|
|
952
|
-
try {
|
|
953
|
-
await Promise.all([
|
|
954
|
-
createOrSetRabbitTrace(trace, userId),
|
|
955
|
-
createOrSetRabbitTrace(outbreakTrace, userId),
|
|
956
|
-
]);
|
|
957
|
-
} catch (e) {
|
|
958
|
-
logger.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
959
|
-
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
if (traceId) {
|
|
964
|
-
(trace as any)?.context?.set(TRACING_HEADER, traceId);
|
|
965
|
-
(outbreakTrace as any)?.context.set(TRACING_HEADER, traceId);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
if (auditContext) {
|
|
969
|
-
await auditContext(queue, {
|
|
970
|
-
userId,
|
|
971
|
-
automationId,
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
975
|
-
if (!shouldConsume) {
|
|
976
|
-
await this.unlockRedisIfNeeded(releaseLock);
|
|
977
|
-
return this.ack(confirmChannel, msg)(msg);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
let messageAcked = false;
|
|
981
|
-
// setting the localAck function to be used in the callback
|
|
982
|
-
|
|
983
|
-
const localAck = async () => {
|
|
984
|
-
if (messageAcked) {
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
987
|
-
messageAcked = true;
|
|
988
|
-
return this.ack(confirmChannel, msg, true, releaseLock)(msg);
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
|
|
992
|
-
if (messageAcked) {
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
996
|
-
messageAcked = true;
|
|
997
|
-
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
|
|
998
|
-
};
|
|
999
|
-
|
|
1000
|
-
try {
|
|
1001
|
-
await callback(
|
|
1002
|
-
parsedMessage,
|
|
1003
|
-
localAck,
|
|
1004
|
-
localNack,
|
|
1005
|
-
);
|
|
1006
|
-
} catch (e) {
|
|
1007
|
-
await localNack(msg);
|
|
1008
|
-
}
|
|
1009
|
-
}, CONSUMER_DEFAULT_OPTIONS,
|
|
1010
|
-
);
|
|
1011
|
-
if (!consumerTag) {
|
|
1012
|
-
logger.error(`rabbit: failed to consume from queue ${queue}`);
|
|
1013
|
-
} else {
|
|
1014
|
-
logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
1015
|
-
this.oldConsumersTags.push([confirmChannel, consumerTag]);
|
|
1016
|
-
}
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
// TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
|
|
1021
|
-
async getNewChannelOld({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
|
|
1022
|
-
let connection!: AmqpConnectionManager;
|
|
1023
|
-
try {
|
|
1024
|
-
connection = await this.getConnectionOld();
|
|
1025
|
-
} catch (e) {
|
|
1026
|
-
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
1027
|
-
throw e;
|
|
1028
|
-
}
|
|
1029
|
-
const channel = connection.createChannel({ ...options });
|
|
1030
|
-
once(channel, 'close').then((args) => {
|
|
1031
|
-
logger.error(`rabbit: channel ${name} closed`);
|
|
1032
|
-
onClose?.(args);
|
|
1033
|
-
});
|
|
1034
|
-
try {
|
|
1035
|
-
await once(channel, 'connect');
|
|
1036
|
-
debug(`rabbit: channel ${name} CONNECTED`);
|
|
1037
|
-
return channel;
|
|
1038
|
-
} catch (err) {
|
|
1039
|
-
logger.error(`rabbit: channel error ${name} error`, { err });
|
|
1040
|
-
throw err;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
async getConnectionOld() {
|
|
1045
|
-
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
1046
|
-
if (this.oldBlockReconnect) {
|
|
1047
|
-
debug('rabbit: block reconnect');
|
|
1048
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1049
|
-
// @ts-ignore
|
|
1050
|
-
return resolve();
|
|
1051
|
-
}
|
|
1052
|
-
if (this.oldConnection !== null) {
|
|
1053
|
-
if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
|
|
1054
|
-
debug('rabbit: connection - is connected');
|
|
1055
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1056
|
-
// @ts-ignore
|
|
1057
|
-
return resolve(this.oldConnection);
|
|
1058
|
-
}
|
|
1059
|
-
debug('rabbit: connection - reconnecting');
|
|
1060
|
-
}
|
|
1061
|
-
if (this.oldCreatingConnection) {
|
|
1062
|
-
debug('rabbit: creating connection emi');
|
|
1063
|
-
this.oldEm.once(CONNECTION_CREATED_CONST, resolve);
|
|
1064
|
-
this.oldEm.once(CONNECTION_FAILED_CONST, reject);
|
|
1065
|
-
return;
|
|
1066
|
-
}
|
|
1067
|
-
this.oldCreatingConnection = true;
|
|
1068
|
-
let isResolved = false;
|
|
1069
|
-
|
|
1070
|
-
// It is import to use it as a function and not as a variable
|
|
1071
|
-
// because of k8s changes the env variables
|
|
1072
|
-
// and we want to use the new values
|
|
1073
|
-
const findServers = () => {
|
|
1074
|
-
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
1075
|
-
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
1076
|
-
const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
|
|
1077
|
-
|
|
1078
|
-
debug('rabbit: creating connection', { host, userName, HEARTBEAT });
|
|
1079
|
-
|
|
1080
|
-
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
1081
|
-
};
|
|
1082
|
-
|
|
1083
|
-
const defaultUrls = findServers();
|
|
1084
|
-
const connection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
1085
|
-
findServers,
|
|
1086
|
-
});
|
|
1087
|
-
|
|
1088
|
-
this.oldConnection = connection;
|
|
1089
|
-
this.oldConnection.on('error', (err) => {
|
|
1090
|
-
logger.error('rabbit: connection error', { err });
|
|
1091
|
-
if (!isResolved) {
|
|
1092
|
-
isResolved = true;
|
|
1093
|
-
reject(err);
|
|
1094
|
-
this.oldEm.emit(CONNECTION_FAILED_CONST, err);
|
|
1095
|
-
}
|
|
1096
|
-
});
|
|
1097
|
-
|
|
1098
|
-
this.oldConnection.on('connectFailed', (err) => {
|
|
1099
|
-
this.oldConsumersTags = [];
|
|
1100
|
-
if (typeof err.url === 'string') {
|
|
1101
|
-
err.url = this.maskURL(err.url);
|
|
1102
|
-
}
|
|
1103
|
-
logger.error('rabbit: connection connectFailed', { err });
|
|
1104
|
-
if (!isResolved) {
|
|
1105
|
-
isResolved = true;
|
|
1106
|
-
reject(err);
|
|
1107
|
-
this.oldEm.emit(CONNECTION_FAILED_CONST, err);
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
this.oldConnection.on('disconnect', ({ err }) => {
|
|
1112
|
-
this.oldConsumersTags = [];
|
|
1113
|
-
debug('rabbit: connection closed');
|
|
1114
|
-
if (this.options?.disableReconnect) {
|
|
1115
|
-
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
1116
|
-
this.oldBlockReconnect = true;
|
|
1117
|
-
} else {
|
|
1118
|
-
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
1119
|
-
}
|
|
1120
|
-
});
|
|
1121
|
-
|
|
1122
|
-
this.oldConnection.once('connect', async () => {
|
|
1123
|
-
debug('rabbit: connection established');
|
|
1124
|
-
this.oldCreatingConnection = false;
|
|
1125
|
-
this.oldEm.emit(CONNECTION_CREATED_CONST, connection);
|
|
1126
|
-
isResolved = true;
|
|
1127
|
-
resolve(connection);
|
|
1128
|
-
});
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
private saveConsumerOld(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
|
|
1133
|
-
const isConsumerExist :boolean = this.oldConsumers.some((consumer) => consumer.queue === queue);
|
|
1134
|
-
if (!isConsumerExist) {
|
|
1135
|
-
logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
1136
|
-
this.oldConsumers.push({
|
|
1137
|
-
queue,
|
|
1138
|
-
callback,
|
|
1139
|
-
options,
|
|
1140
|
-
});
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
async assertQueueOld(queueName: string, options?: Options.AssertQueue): Promise<any> {
|
|
1145
|
-
RabbitMq.validateName('queue', queueName);
|
|
1146
|
-
if (this.oldQueues[queueName]) {
|
|
1147
|
-
delete this.oldQueueSetupPromises[queueName];
|
|
1148
|
-
return this.oldQueues[queueName];
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
if (this.oldQueueSetupPromises[queueName]) {
|
|
1152
|
-
return this.oldQueueSetupPromises[queueName];
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
this.oldQueueSetupPromises[queueName] = this.setupQueueOld(queueName, options);
|
|
1156
|
-
return this.oldQueueSetupPromises[queueName];
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
1160
|
-
let queue: Replies.AssertQueue;
|
|
1161
|
-
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
1162
|
-
const localeOptions = {
|
|
1163
|
-
...options,
|
|
1164
|
-
durable: true,
|
|
1165
|
-
arguments: {
|
|
1166
|
-
...options?.arguments,
|
|
1167
|
-
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
1168
|
-
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
1169
|
-
},
|
|
1170
|
-
};
|
|
1171
|
-
try {
|
|
1172
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1173
|
-
debug('assertQueue->channel.addSetup', { queueName });
|
|
1174
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1175
|
-
debug('assertQueue->channel.assertQueue', { queueName });
|
|
1176
|
-
queue = await channel.assertQueue(queueName, localeOptions);
|
|
1177
|
-
} catch (e) {
|
|
1178
|
-
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
1179
|
-
if (!this.options?.dontRetryAssert) {
|
|
1180
|
-
debug('retrying assertQueue', { queueName });
|
|
1181
|
-
const channel = await this.assertChannelOld({ force: true });
|
|
1182
|
-
await this.deleteQueueOld(queueName);
|
|
1183
|
-
|
|
1184
|
-
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
1185
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1186
|
-
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
1187
|
-
queue = await channel.assertQueue(queueName, localeOptions);
|
|
1188
|
-
} else {
|
|
1189
|
-
throw e;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
this.oldQueues[queueName] = queue;
|
|
1194
|
-
return queue;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
async assertChannelOld({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
|
|
1198
|
-
if (!this.oldPublishChannelSetupPromise) {
|
|
1199
|
-
this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
1200
|
-
if (this.oldChannel && !force) {
|
|
1201
|
-
return resolve(this.oldChannel);
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
try {
|
|
1205
|
-
const channel = await this.getNewChannelOld({});
|
|
1206
|
-
channel.on('error', (err) => {
|
|
1207
|
-
logger.error('rabbit: channel error', { err });
|
|
1208
|
-
});
|
|
1209
|
-
this.oldChannel = channel;
|
|
1210
|
-
resolve(channel);
|
|
1211
|
-
} catch (e) {
|
|
1212
|
-
reject(e);
|
|
1213
|
-
}
|
|
1214
|
-
});
|
|
1215
|
-
}
|
|
1216
|
-
return this.oldPublishChannelSetupPromise;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
private async deleteQueueOld(queue: string) {
|
|
1220
|
-
RabbitMq.validateName('queue', queue);
|
|
1221
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1222
|
-
logger.info('rabbit: deleting queue', { queue });
|
|
1223
|
-
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
1224
|
-
debug('queue deleted', deleteQueueRes);
|
|
1225
|
-
return deleteQueueRes;
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
async assertExchangeOld(exchangeName: string, options?: any) {
|
|
1229
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1230
|
-
|
|
1231
|
-
if (this.oldExchanges[exchangeName]) {
|
|
1232
|
-
delete this.oldAssertExchangePromises[exchangeName];
|
|
1233
|
-
return this.oldExchanges[exchangeName];
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
if (this.oldAssertExchangePromises[exchangeName]) {
|
|
1237
|
-
return this.oldAssertExchangePromises[exchangeName];
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
this.oldAssertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
|
|
1241
|
-
this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
|
|
1242
|
-
return this.oldExchanges[exchangeName];
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
private maskURL = (url: string): string => {
|
|
1246
|
-
try {
|
|
1247
|
-
const urlObj = new URL(url);
|
|
1248
|
-
urlObj.username = '***';
|
|
1249
|
-
urlObj.password = '***';
|
|
1250
|
-
return urlObj.toString();
|
|
1251
|
-
} catch {
|
|
1252
|
-
return url;
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
836
|
}
|
|
1256
837
|
|
|
1257
838
|
export default RabbitMq;
|
|
1258
|
-
|
|
1259
|
-
export {
|
|
1260
|
-
sendCeleryTaskViaHttp,
|
|
1261
|
-
} from './lib/celery';
|