@autofleet/rabbit 3.4.0-beta--beta--0.0 → 3.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -14
- package/dist/index.js +139 -129
- package/dist/lib/consts.d.ts +0 -2
- package/dist/lib/consts.js +1 -3
- package/dist/lib/types.d.ts +8 -0
- package/package.json +1 -1
- package/src/index.ts +167 -146
- package/src/lib/consts.ts +0 -2
- package/src/lib/types.ts +9 -0
package/src/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars */
|
|
2
|
-
|
|
1
|
+
/* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars,no-param-reassign */
|
|
3
2
|
import { EventEmitter, once } from 'events';
|
|
4
3
|
import { promisify } from 'util';
|
|
5
4
|
import moment from 'moment';
|
|
@@ -20,8 +19,6 @@ import getRedisInstance, { RedisConfig } from './lib/redis';
|
|
|
20
19
|
import { assertExchangeFanout, rand, wrapSetImmediate } from './lib/utils';
|
|
21
20
|
import {
|
|
22
21
|
AUTOMATION_ID_HEADER,
|
|
23
|
-
CONNECTION_CREATED_CONST,
|
|
24
|
-
CONNECTION_FAILED_CONST,
|
|
25
22
|
DEFAULT_LOCK_TIMEOUT,
|
|
26
23
|
DEFAULT_OPTIONS,
|
|
27
24
|
RETRY_HEADER,
|
|
@@ -40,8 +37,8 @@ import {
|
|
|
40
37
|
CONSUMER_DEFAULT_OPTIONS,
|
|
41
38
|
QueueSetupPromisesDictionary,
|
|
42
39
|
AssertExchangePromisesDictionary,
|
|
40
|
+
ConnectionData,
|
|
43
41
|
} from './lib/types';
|
|
44
|
-
import { SendTaskOptions, TaskData } from './lib/celery';
|
|
45
42
|
|
|
46
43
|
// const debug = nodeDebug('af-rabbitmq')
|
|
47
44
|
const debug = logger.debug.bind(logger);
|
|
@@ -87,11 +84,13 @@ type newChannelOpts = {
|
|
|
87
84
|
name?: string;
|
|
88
85
|
onClose?: null | ((args: any | null) => void);
|
|
89
86
|
options?: CreateChannelOpts | undefined;
|
|
87
|
+
connection: ConnectionData;
|
|
90
88
|
};
|
|
91
89
|
|
|
92
90
|
type assertChannelOpts = {
|
|
93
91
|
channelName?: string;
|
|
94
92
|
force?: boolean;
|
|
93
|
+
connection: ConnectionData;
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
type AfConsumer = {
|
|
@@ -144,7 +143,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
144
143
|
|
|
145
144
|
RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
146
145
|
|
|
147
|
-
|
|
146
|
+
publishChannel: ChannelWrapper | null;
|
|
148
147
|
|
|
149
148
|
publishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
150
149
|
|
|
@@ -152,6 +151,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
152
151
|
|
|
153
152
|
connection: AmqpConnectionManager | null | undefined
|
|
154
153
|
|
|
154
|
+
publishConnection: ConnectionData
|
|
155
|
+
|
|
156
|
+
consumeConnection: ConnectionData
|
|
157
|
+
|
|
155
158
|
em: EventEmitter;
|
|
156
159
|
|
|
157
160
|
creatingConnection: boolean;
|
|
@@ -180,13 +183,15 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
180
183
|
private vhost = 'quorum-vhost';
|
|
181
184
|
|
|
182
185
|
// TODO:[QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
|
|
183
|
-
|
|
186
|
+
oldPublishChannel: ChannelWrapper | null;
|
|
184
187
|
|
|
185
188
|
oldPublishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
186
189
|
|
|
187
190
|
oldBlockReconnect: boolean | null | undefined
|
|
188
191
|
|
|
189
|
-
|
|
192
|
+
oldPublishConnection: ConnectionData
|
|
193
|
+
|
|
194
|
+
oldConsumeConnection: ConnectionData
|
|
190
195
|
|
|
191
196
|
oldEm: EventEmitter;
|
|
192
197
|
|
|
@@ -206,9 +211,23 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
206
211
|
|
|
207
212
|
constructor(options: AfRabbitOptions = {}, redisConfig?: RedisConfig) {
|
|
208
213
|
this.em = new EventEmitter();
|
|
209
|
-
this.
|
|
214
|
+
this.publishChannel = null;
|
|
210
215
|
this.publishChannelSetupPromise = null;
|
|
211
216
|
this.connection = null;
|
|
217
|
+
this.publishConnection = {
|
|
218
|
+
connection: null,
|
|
219
|
+
creatingConnection: false,
|
|
220
|
+
connectionCreatedEventName: 'publishConnectionCreated',
|
|
221
|
+
connectionFailedEventName: 'publishConnectionFailed',
|
|
222
|
+
blockReconnect: false,
|
|
223
|
+
};
|
|
224
|
+
this.consumeConnection = {
|
|
225
|
+
connection: null,
|
|
226
|
+
creatingConnection: false,
|
|
227
|
+
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
228
|
+
connectionFailedEventName: 'consumeConnectionFailed',
|
|
229
|
+
blockReconnect: false,
|
|
230
|
+
};
|
|
212
231
|
this.creatingConnection = false;
|
|
213
232
|
this.exchanges = {};
|
|
214
233
|
this.queues = {};
|
|
@@ -234,9 +253,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
234
253
|
|
|
235
254
|
// TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
|
|
236
255
|
this.oldEm = new EventEmitter();
|
|
237
|
-
this.
|
|
256
|
+
this.oldPublishChannel = null;
|
|
238
257
|
this.oldPublishChannelSetupPromise = null;
|
|
239
|
-
this.
|
|
258
|
+
this.oldPublishConnection = {
|
|
259
|
+
connection: null,
|
|
260
|
+
creatingConnection: false,
|
|
261
|
+
connectionCreatedEventName: 'publishConnectionCreated',
|
|
262
|
+
connectionFailedEventName: 'publishConnectionFailed',
|
|
263
|
+
blockReconnect: false,
|
|
264
|
+
};
|
|
265
|
+
this.oldConsumeConnection = {
|
|
266
|
+
connection: null,
|
|
267
|
+
creatingConnection: false,
|
|
268
|
+
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
269
|
+
connectionFailedEventName: 'consumeConnectionFailed',
|
|
270
|
+
blockReconnect: false,
|
|
271
|
+
};
|
|
240
272
|
this.oldCreatingConnection = false;
|
|
241
273
|
this.oldExchanges = {};
|
|
242
274
|
this.oldQueues = {};
|
|
@@ -374,30 +406,37 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
374
406
|
}
|
|
375
407
|
}
|
|
376
408
|
|
|
377
|
-
async getConnection() {
|
|
409
|
+
async getConnection(connection: ConnectionData) {
|
|
378
410
|
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
379
|
-
|
|
411
|
+
const {
|
|
412
|
+
connection: connectionLocal,
|
|
413
|
+
creatingConnection,
|
|
414
|
+
connectionCreatedEventName,
|
|
415
|
+
connectionFailedEventName,
|
|
416
|
+
blockReconnect,
|
|
417
|
+
} = connection;
|
|
418
|
+
if (blockReconnect) {
|
|
380
419
|
debug('rabbit: block reconnect');
|
|
381
420
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
382
421
|
// @ts-ignore
|
|
383
422
|
return resolve();
|
|
384
423
|
}
|
|
385
|
-
if (
|
|
386
|
-
if (this.options?.disableReconnect ||
|
|
424
|
+
if (connectionLocal !== null) {
|
|
425
|
+
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
387
426
|
debug('rabbit: connection - is connected');
|
|
388
427
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
389
428
|
// @ts-ignore
|
|
390
|
-
return resolve(
|
|
429
|
+
return resolve(connectionLocal);
|
|
391
430
|
}
|
|
392
431
|
debug('rabbit: connection - reconnecting');
|
|
393
432
|
}
|
|
394
|
-
if (
|
|
433
|
+
if (creatingConnection) {
|
|
395
434
|
debug('rabbit: creating connection emi');
|
|
396
|
-
this.em.once(
|
|
397
|
-
this.em.once(
|
|
435
|
+
this.em.once(connectionCreatedEventName, resolve);
|
|
436
|
+
this.em.once(connectionFailedEventName, reject);
|
|
398
437
|
return;
|
|
399
438
|
}
|
|
400
|
-
|
|
439
|
+
connection.creatingConnection = true;
|
|
401
440
|
let isResolved = false;
|
|
402
441
|
|
|
403
442
|
// It is import to use it as a function and not as a variable
|
|
@@ -413,61 +452,63 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
413
452
|
};
|
|
414
453
|
|
|
415
454
|
const defaultUrls = findServers();
|
|
416
|
-
const
|
|
455
|
+
const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
417
456
|
findServers,
|
|
418
457
|
});
|
|
419
458
|
|
|
420
|
-
|
|
421
|
-
|
|
459
|
+
connection.connection = newConnection;
|
|
460
|
+
newConnection.on('error', (err) => {
|
|
422
461
|
logger.error('rabbit: connection error', { err });
|
|
423
462
|
if (!isResolved) {
|
|
424
463
|
isResolved = true;
|
|
425
464
|
reject(err);
|
|
426
|
-
this.em.emit(
|
|
465
|
+
this.em.emit(connectionFailedEventName, err);
|
|
427
466
|
}
|
|
428
467
|
});
|
|
429
468
|
|
|
430
|
-
|
|
469
|
+
newConnection.on('connectFailed', (err) => {
|
|
431
470
|
this.consumersTags = [];
|
|
432
471
|
logger.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
|
|
433
472
|
if (!isResolved) {
|
|
434
473
|
isResolved = true;
|
|
435
474
|
reject(err);
|
|
436
|
-
this.em.emit(
|
|
475
|
+
this.em.emit(connectionFailedEventName, err);
|
|
437
476
|
}
|
|
438
477
|
});
|
|
439
478
|
|
|
440
|
-
|
|
441
|
-
|
|
479
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
480
|
+
// this.publishChannel = null;
|
|
442
481
|
this.consumersTags = [];
|
|
443
482
|
debug('rabbit: connection closed');
|
|
444
483
|
if (this.options?.disableReconnect) {
|
|
445
484
|
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
446
|
-
|
|
485
|
+
connection.blockReconnect = true;
|
|
447
486
|
} else {
|
|
448
487
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
449
488
|
}
|
|
450
489
|
});
|
|
451
490
|
|
|
452
|
-
|
|
491
|
+
newConnection.once('connect', async () => {
|
|
453
492
|
debug('rabbit: connection established');
|
|
454
|
-
|
|
455
|
-
this.em.emit(
|
|
493
|
+
connection.creatingConnection = false;
|
|
494
|
+
this.em.emit(connectionCreatedEventName, connection);
|
|
456
495
|
isResolved = true;
|
|
457
|
-
resolve(
|
|
496
|
+
resolve(newConnection);
|
|
458
497
|
});
|
|
459
498
|
});
|
|
460
499
|
}
|
|
461
500
|
|
|
462
|
-
async getNewChannel({
|
|
463
|
-
|
|
501
|
+
async getNewChannel({
|
|
502
|
+
name = rand().toString(), onClose = null, options = {}, connection,
|
|
503
|
+
}: newChannelOpts) {
|
|
504
|
+
let localConnection!: AmqpConnectionManager;
|
|
464
505
|
try {
|
|
465
|
-
|
|
506
|
+
localConnection = await this.getConnection(connection);
|
|
466
507
|
} catch (e) {
|
|
467
508
|
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
468
509
|
throw e;
|
|
469
510
|
}
|
|
470
|
-
const channel =
|
|
511
|
+
const channel = localConnection.createChannel({ ...options });
|
|
471
512
|
once(channel, 'close').then((args) => {
|
|
472
513
|
logger.error(`rabbit: channel ${name} closed`);
|
|
473
514
|
onClose?.(args);
|
|
@@ -482,19 +523,21 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
482
523
|
}
|
|
483
524
|
}
|
|
484
525
|
|
|
485
|
-
async assertChannel({ force = false }
|
|
526
|
+
async assertChannel({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
486
527
|
if (!this.publishChannelSetupPromise) {
|
|
487
528
|
this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
488
|
-
if (this.
|
|
489
|
-
return resolve(this.
|
|
529
|
+
if (this.publishChannel && !force) {
|
|
530
|
+
return resolve(this.publishChannel);
|
|
490
531
|
}
|
|
491
532
|
|
|
492
533
|
try {
|
|
493
|
-
const channel = await this.getNewChannel({});
|
|
534
|
+
const channel = await this.getNewChannel({ connection });
|
|
494
535
|
channel.on('error', (err) => {
|
|
495
536
|
logger.error('rabbit: channel error', { err });
|
|
496
537
|
});
|
|
497
|
-
this.
|
|
538
|
+
if (this.publishConnection === connection) {
|
|
539
|
+
this.publishChannel = channel;
|
|
540
|
+
}
|
|
498
541
|
resolve(channel);
|
|
499
542
|
} catch (e) {
|
|
500
543
|
reject(e);
|
|
@@ -504,8 +547,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
504
547
|
return this.publishChannelSetupPromise;
|
|
505
548
|
}
|
|
506
549
|
|
|
507
|
-
async assertExchange(exchangeName: string,
|
|
508
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
550
|
+
async assertExchange(exchangeName: string, connection: ConnectionData) {
|
|
551
|
+
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
509
552
|
|
|
510
553
|
if (this.exchanges[exchangeName]) {
|
|
511
554
|
delete this.assertExchangePromises[exchangeName];
|
|
@@ -524,7 +567,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
524
567
|
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
525
568
|
async getQueueLength(queue: string) {
|
|
526
569
|
RabbitMq.validateName('queue', queue);
|
|
527
|
-
const {
|
|
570
|
+
const { oldPublishChannel: channel } = this;
|
|
528
571
|
if (!channel) {
|
|
529
572
|
throw new RabbitError('channel is not defined');
|
|
530
573
|
}
|
|
@@ -532,9 +575,9 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
532
575
|
return channel?.checkQueue(queue);
|
|
533
576
|
}
|
|
534
577
|
|
|
535
|
-
private async deleteQueue(queue: string) {
|
|
578
|
+
private async deleteQueue(queue: string, connection: ConnectionData) {
|
|
536
579
|
RabbitMq.validateName('queue', queue);
|
|
537
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
580
|
+
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
538
581
|
logger.info('rabbit: deleting queue', { queue });
|
|
539
582
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
540
583
|
debug('queue deleted', deleteQueueRes);
|
|
@@ -543,13 +586,14 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
543
586
|
|
|
544
587
|
// TODO: [QUORUM-PHASE-2] Change the implementation to the new one
|
|
545
588
|
async bindQueue(queue: string, exchange: string) {
|
|
546
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
589
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
547
590
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
548
591
|
return channel.bindQueue(queue, exchange, '');
|
|
549
592
|
}
|
|
550
593
|
|
|
551
594
|
async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
552
595
|
let queue: Replies.AssertQueue;
|
|
596
|
+
const connection = this.publishConnection;
|
|
553
597
|
const localeOptions = {
|
|
554
598
|
...options,
|
|
555
599
|
durable: true,
|
|
@@ -560,7 +604,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
560
604
|
},
|
|
561
605
|
};
|
|
562
606
|
try {
|
|
563
|
-
const channel: ChannelWrapper = await this.assertChannel();
|
|
607
|
+
const channel: ChannelWrapper = await this.assertChannel({ connection });
|
|
564
608
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
565
609
|
await channel.addSetup(async (setupChannel: ConfirmChannel) => {
|
|
566
610
|
await setupChannel.assertQueue(queueName, localeOptions);
|
|
@@ -571,8 +615,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
571
615
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
572
616
|
if (!this.options?.dontRetryAssert) {
|
|
573
617
|
debug('retrying assertQueue', { queueName });
|
|
574
|
-
const channel = await this.assertChannel({ force: true });
|
|
575
|
-
await this.deleteQueue(queueName);
|
|
618
|
+
const channel = await this.assertChannel({ force: true, connection });
|
|
619
|
+
await this.deleteQueue(queueName, connection);
|
|
576
620
|
|
|
577
621
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
578
622
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
@@ -685,7 +729,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
685
729
|
}
|
|
686
730
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
687
731
|
}
|
|
688
|
-
const channel = await this.getNewChannel({});
|
|
732
|
+
const channel = await this.getNewChannel({ connection: this.consumeConnection });
|
|
689
733
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
690
734
|
const q = await this.assertQueue(queue, optionsWithDefaults);
|
|
691
735
|
await confirmChannel.prefetch(limit, false);
|
|
@@ -785,7 +829,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
785
829
|
if (options?.isQuorumQueue !== false) {
|
|
786
830
|
await this.assertVHost();
|
|
787
831
|
await this.saveConsumer(queue, callback, options);
|
|
788
|
-
const channel: ChannelWrapper = await this.getNewChannel({
|
|
832
|
+
const channel: ChannelWrapper = await this.getNewChannel({
|
|
833
|
+
name: `consume-exchange-${exchange}-queue-${queue}`,
|
|
834
|
+
connection: this.consumeConnection,
|
|
835
|
+
});
|
|
789
836
|
|
|
790
837
|
await channel.addSetup(async (c: ConfirmChannel) => {
|
|
791
838
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
@@ -805,7 +852,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
805
852
|
|
|
806
853
|
// TODO: [QUORUM-PHASE-3] Delete the old implementation
|
|
807
854
|
await this.saveConsumerOld(queue, callback, options);
|
|
808
|
-
const channelOld: ChannelWrapper = await this.getNewChannelOld({
|
|
855
|
+
const channelOld: ChannelWrapper = await this.getNewChannelOld({
|
|
856
|
+
name: `consume-exchange-${exchange}-queue-${queue}-old`,
|
|
857
|
+
connection: this.oldConsumeConnection,
|
|
858
|
+
});
|
|
809
859
|
await channelOld.addSetup(async (c: ConfirmChannel) => {
|
|
810
860
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
811
861
|
await c.assertQueue(queue);
|
|
@@ -827,8 +877,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
827
877
|
async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
|
|
828
878
|
return wrapSetImmediate(async () => {
|
|
829
879
|
RabbitMq.validateName('exchange', exchange);
|
|
830
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
831
|
-
await this.assertExchangeOld(exchange);
|
|
880
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
881
|
+
await this.assertExchangeOld(exchange, this.oldPublishConnection);
|
|
832
882
|
await channel.publish(exchange, '',
|
|
833
883
|
Buffer.from(JSON.stringify(content)),
|
|
834
884
|
RabbitMq.getPublishOptions(customHeaders));
|
|
@@ -844,7 +894,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
844
894
|
customHeaders?: any,
|
|
845
895
|
): Promise<boolean | undefined> {
|
|
846
896
|
try {
|
|
847
|
-
await this.assertChannelOld();
|
|
897
|
+
await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
848
898
|
} catch (e) {
|
|
849
899
|
logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
850
900
|
throw e;
|
|
@@ -859,7 +909,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
859
909
|
}
|
|
860
910
|
|
|
861
911
|
try {
|
|
862
|
-
const res = await this.
|
|
912
|
+
const res = await this.oldPublishChannel?.sendToQueue(queue,
|
|
863
913
|
Buffer.from(JSON.stringify(content)),
|
|
864
914
|
RabbitMq.getPublishOptions(customHeaders));
|
|
865
915
|
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
@@ -871,61 +921,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
871
921
|
}
|
|
872
922
|
}
|
|
873
923
|
|
|
874
|
-
async sendToCeleryQueue(
|
|
875
|
-
data: TaskData,
|
|
876
|
-
taskName: string,
|
|
877
|
-
queueName: string,
|
|
878
|
-
): Promise<boolean | undefined> {
|
|
879
|
-
const taskId = randomUUID();
|
|
880
|
-
|
|
881
|
-
// Celery-compatible message body
|
|
882
|
-
const taskPayload = {
|
|
883
|
-
task: taskName,
|
|
884
|
-
id: taskId,
|
|
885
|
-
args: [data],
|
|
886
|
-
kwargs: {},
|
|
887
|
-
retries: 0,
|
|
888
|
-
eta: null,
|
|
889
|
-
};
|
|
890
|
-
|
|
891
|
-
// Celery-compatible AMQP headers
|
|
892
|
-
const publishOptions = {
|
|
893
|
-
contentType: 'application/json',
|
|
894
|
-
contentEncoding: 'utf-8',
|
|
895
|
-
deliveryMode: 2, // persistent
|
|
896
|
-
headers: {
|
|
897
|
-
lang: 'py',
|
|
898
|
-
task: taskName,
|
|
899
|
-
id: taskId,
|
|
900
|
-
root_id: taskId,
|
|
901
|
-
parent_id: null,
|
|
902
|
-
group: null,
|
|
903
|
-
retries: 0,
|
|
904
|
-
eta: null,
|
|
905
|
-
},
|
|
906
|
-
};
|
|
907
|
-
|
|
908
|
-
try {
|
|
909
|
-
return await this.sendToQueue(queueName, taskPayload, undefined, publishOptions);
|
|
910
|
-
} catch (e) {
|
|
911
|
-
const isConnected = await this.isConnected();
|
|
912
|
-
logger.error(
|
|
913
|
-
`rabbit sendToQueue: failed to send to queue ${queueName}, isConnected: ${isConnected}`,
|
|
914
|
-
{ e },
|
|
915
|
-
);
|
|
916
|
-
throw e;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
|
|
920
924
|
// TODO: [QUORUM-PHASE-2] After changing the publish from old to new change from the old to the new implementation
|
|
921
925
|
async isConnected() : Promise<boolean> {
|
|
922
|
-
|
|
923
|
-
const
|
|
926
|
+
debug('rabbit: start is connected');
|
|
927
|
+
const consumeConnection = await this.getConnectionOld(this.oldConsumeConnection);
|
|
928
|
+
const publishConnection = await this.getConnectionOld(this.oldPublishConnection);
|
|
929
|
+
const isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
|
|
924
930
|
if (!isConnected) {
|
|
925
931
|
logger.error('rabbit: isConnected - false');
|
|
926
932
|
return false;
|
|
927
933
|
}
|
|
928
|
-
const channel: any = await this.assertChannelOld();
|
|
934
|
+
const channel: any = await this.assertChannelOld({ connection: this.oldPublishConnection });
|
|
929
935
|
try {
|
|
930
936
|
await Promise.all([
|
|
931
937
|
channel.waitForConnect(),
|
|
@@ -935,7 +941,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
935
941
|
logger.error('rabbit: isConnected - false');
|
|
936
942
|
return false;
|
|
937
943
|
}
|
|
938
|
-
logger.
|
|
944
|
+
logger.debug('rabbit: isConnected - true');
|
|
939
945
|
return true;
|
|
940
946
|
}
|
|
941
947
|
|
|
@@ -971,7 +977,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
971
977
|
}
|
|
972
978
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
973
979
|
}
|
|
974
|
-
const channel = await this.getNewChannelOld({});
|
|
980
|
+
const channel = await this.getNewChannelOld({ connection: this.oldConsumeConnection });
|
|
975
981
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
976
982
|
const q = await this.assertQueueOld(queue, optionsWithDefaults);
|
|
977
983
|
await confirmChannel.prefetch(limit, false);
|
|
@@ -1062,15 +1068,18 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1062
1068
|
}
|
|
1063
1069
|
|
|
1064
1070
|
// TODO: [QUORUM-PHASE-3] Delete all the function under this line (getNewChannelOld, getConnectionOld, assertQueueOld, setupQueueOld, saveConsumerOld)
|
|
1065
|
-
async getNewChannelOld({
|
|
1066
|
-
|
|
1071
|
+
async getNewChannelOld({
|
|
1072
|
+
name = rand().toString(), onClose = null, options = {}, connection,
|
|
1073
|
+
}: newChannelOpts) {
|
|
1074
|
+
let localConnection!: AmqpConnectionManager;
|
|
1067
1075
|
try {
|
|
1068
|
-
|
|
1076
|
+
localConnection = await this.getConnectionOld(connection);
|
|
1069
1077
|
} catch (e) {
|
|
1070
1078
|
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
1071
1079
|
throw e;
|
|
1072
1080
|
}
|
|
1073
|
-
|
|
1081
|
+
debug('rabbit: getNewChannelOld', { localConnection });
|
|
1082
|
+
const channel = localConnection.createChannel({ ...options });
|
|
1074
1083
|
once(channel, 'close').then((args) => {
|
|
1075
1084
|
logger.error(`rabbit: channel ${name} closed`);
|
|
1076
1085
|
onClose?.(args);
|
|
@@ -1085,30 +1094,38 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1085
1094
|
}
|
|
1086
1095
|
}
|
|
1087
1096
|
|
|
1088
|
-
async getConnectionOld() {
|
|
1097
|
+
async getConnectionOld(connection: ConnectionData) {
|
|
1089
1098
|
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
1090
|
-
|
|
1099
|
+
const {
|
|
1100
|
+
connection: connectionLocal,
|
|
1101
|
+
creatingConnection,
|
|
1102
|
+
connectionCreatedEventName,
|
|
1103
|
+
connectionFailedEventName,
|
|
1104
|
+
blockReconnect,
|
|
1105
|
+
} = connection;
|
|
1106
|
+
debug('rabbit: getConnectionOld', { connectionLocal, creatingConnection, blockReconnect });
|
|
1107
|
+
if (blockReconnect) {
|
|
1091
1108
|
debug('rabbit: block reconnect');
|
|
1092
1109
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1093
1110
|
// @ts-ignore
|
|
1094
1111
|
return resolve();
|
|
1095
1112
|
}
|
|
1096
|
-
if (
|
|
1097
|
-
if (this.options?.disableReconnect ||
|
|
1113
|
+
if (connectionLocal !== null) {
|
|
1114
|
+
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
1098
1115
|
debug('rabbit: connection - is connected');
|
|
1099
1116
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1100
1117
|
// @ts-ignore
|
|
1101
|
-
return resolve(
|
|
1118
|
+
return resolve(connectionLocal);
|
|
1102
1119
|
}
|
|
1103
1120
|
debug('rabbit: connection - reconnecting');
|
|
1104
1121
|
}
|
|
1105
|
-
if (
|
|
1122
|
+
if (creatingConnection) {
|
|
1106
1123
|
debug('rabbit: creating connection emi');
|
|
1107
|
-
this.oldEm.once(
|
|
1108
|
-
this.oldEm.once(
|
|
1124
|
+
this.oldEm.once(connectionCreatedEventName, resolve);
|
|
1125
|
+
this.oldEm.once(connectionFailedEventName, reject);
|
|
1109
1126
|
return;
|
|
1110
1127
|
}
|
|
1111
|
-
|
|
1128
|
+
connection.creatingConnection = true;
|
|
1112
1129
|
let isResolved = false;
|
|
1113
1130
|
|
|
1114
1131
|
// It is import to use it as a function and not as a variable
|
|
@@ -1125,47 +1142,47 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1125
1142
|
};
|
|
1126
1143
|
|
|
1127
1144
|
const defaultUrls = findServers();
|
|
1128
|
-
const
|
|
1145
|
+
const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
1129
1146
|
findServers,
|
|
1130
1147
|
});
|
|
1131
1148
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1149
|
+
connection.connection = newConnection;
|
|
1150
|
+
newConnection.on('error', (err) => {
|
|
1134
1151
|
logger.error('rabbit: connection error', { err });
|
|
1135
1152
|
if (!isResolved) {
|
|
1136
1153
|
isResolved = true;
|
|
1137
1154
|
reject(err);
|
|
1138
|
-
this.oldEm.emit(
|
|
1155
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1139
1156
|
}
|
|
1140
1157
|
});
|
|
1141
1158
|
|
|
1142
|
-
|
|
1159
|
+
newConnection.on('connectFailed', (err) => {
|
|
1143
1160
|
this.oldConsumersTags = [];
|
|
1144
1161
|
logger.error('rabbit: connection connectFailed', { err });
|
|
1145
1162
|
if (!isResolved) {
|
|
1146
1163
|
isResolved = true;
|
|
1147
1164
|
reject(err);
|
|
1148
|
-
this.oldEm.emit(
|
|
1165
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1149
1166
|
}
|
|
1150
1167
|
});
|
|
1151
1168
|
|
|
1152
|
-
|
|
1169
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
1153
1170
|
this.oldConsumersTags = [];
|
|
1154
1171
|
debug('rabbit: connection closed');
|
|
1155
1172
|
if (this.options?.disableReconnect) {
|
|
1156
1173
|
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
1157
|
-
|
|
1174
|
+
connection.blockReconnect = true;
|
|
1158
1175
|
} else {
|
|
1159
1176
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
1160
1177
|
}
|
|
1161
1178
|
});
|
|
1162
1179
|
|
|
1163
|
-
|
|
1180
|
+
newConnection.once('connect', async () => {
|
|
1164
1181
|
debug('rabbit: connection established');
|
|
1165
|
-
|
|
1166
|
-
this.oldEm.emit(
|
|
1182
|
+
connection.creatingConnection = false;
|
|
1183
|
+
this.oldEm.emit(connectionCreatedEventName, connection);
|
|
1167
1184
|
isResolved = true;
|
|
1168
|
-
resolve(
|
|
1185
|
+
resolve(newConnection);
|
|
1169
1186
|
});
|
|
1170
1187
|
});
|
|
1171
1188
|
}
|
|
@@ -1199,6 +1216,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1199
1216
|
|
|
1200
1217
|
async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
1201
1218
|
let queue: Replies.AssertQueue;
|
|
1219
|
+
const connection = this.oldPublishConnection;
|
|
1202
1220
|
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
1203
1221
|
const localeOptions = {
|
|
1204
1222
|
...options,
|
|
@@ -1210,7 +1228,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1210
1228
|
},
|
|
1211
1229
|
};
|
|
1212
1230
|
try {
|
|
1213
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1231
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1214
1232
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
1215
1233
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1216
1234
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -1219,8 +1237,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1219
1237
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
1220
1238
|
if (!this.options?.dontRetryAssert) {
|
|
1221
1239
|
debug('retrying assertQueue', { queueName });
|
|
1222
|
-
const channel = await this.assertChannelOld({ force: true });
|
|
1223
|
-
await this.deleteQueueOld(queueName);
|
|
1240
|
+
const channel = await this.assertChannelOld({ force: true, connection });
|
|
1241
|
+
await this.deleteQueueOld(queueName, connection);
|
|
1224
1242
|
|
|
1225
1243
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
1226
1244
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
@@ -1235,19 +1253,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1235
1253
|
return queue;
|
|
1236
1254
|
}
|
|
1237
1255
|
|
|
1238
|
-
async assertChannelOld({ force = false }
|
|
1256
|
+
async assertChannelOld({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
1239
1257
|
if (!this.oldPublishChannelSetupPromise) {
|
|
1240
1258
|
this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
1241
|
-
if (this.
|
|
1242
|
-
return resolve(this.
|
|
1259
|
+
if (this.oldPublishChannel && !force) {
|
|
1260
|
+
return resolve(this.oldPublishChannel);
|
|
1243
1261
|
}
|
|
1244
1262
|
|
|
1245
1263
|
try {
|
|
1246
|
-
const channel = await this.getNewChannelOld({});
|
|
1264
|
+
const channel = await this.getNewChannelOld({ connection });
|
|
1247
1265
|
channel.on('error', (err) => {
|
|
1248
1266
|
logger.error('rabbit: channel error', { err });
|
|
1249
1267
|
});
|
|
1250
|
-
this.
|
|
1268
|
+
if (this.oldPublishConnection === connection) {
|
|
1269
|
+
debug('rabbit: a new channel assigned to the oldPublishChannel', { connection });
|
|
1270
|
+
this.oldPublishChannel = channel;
|
|
1271
|
+
}
|
|
1251
1272
|
resolve(channel);
|
|
1252
1273
|
} catch (e) {
|
|
1253
1274
|
reject(e);
|
|
@@ -1257,17 +1278,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1257
1278
|
return this.oldPublishChannelSetupPromise;
|
|
1258
1279
|
}
|
|
1259
1280
|
|
|
1260
|
-
private async deleteQueueOld(queue: string) {
|
|
1281
|
+
private async deleteQueueOld(queue: string, connection: ConnectionData) {
|
|
1261
1282
|
RabbitMq.validateName('queue', queue);
|
|
1262
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1283
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1263
1284
|
logger.info('rabbit: deleting queue', { queue });
|
|
1264
1285
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
1265
1286
|
debug('queue deleted', deleteQueueRes);
|
|
1266
1287
|
return deleteQueueRes;
|
|
1267
1288
|
}
|
|
1268
1289
|
|
|
1269
|
-
async assertExchangeOld(exchangeName: string,
|
|
1270
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1290
|
+
async assertExchangeOld(exchangeName: string, connection: ConnectionData) {
|
|
1291
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1271
1292
|
|
|
1272
1293
|
if (this.oldExchanges[exchangeName]) {
|
|
1273
1294
|
delete this.oldAssertExchangePromises[exchangeName];
|