@autofleet/rabbit 3.4.0-beta--beta--0.0 → 3.4.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/dist/index.d.ts +17 -14
- package/dist/index.js +137 -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 +165 -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,17 @@ 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
|
-
const channel =
|
|
1081
|
+
const channel = localConnection.createChannel({ ...options });
|
|
1074
1082
|
once(channel, 'close').then((args) => {
|
|
1075
1083
|
logger.error(`rabbit: channel ${name} closed`);
|
|
1076
1084
|
onClose?.(args);
|
|
@@ -1085,30 +1093,37 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1085
1093
|
}
|
|
1086
1094
|
}
|
|
1087
1095
|
|
|
1088
|
-
async getConnectionOld() {
|
|
1096
|
+
async getConnectionOld(connection: ConnectionData) {
|
|
1089
1097
|
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
1090
|
-
|
|
1098
|
+
const {
|
|
1099
|
+
connection: connectionLocal,
|
|
1100
|
+
creatingConnection,
|
|
1101
|
+
connectionCreatedEventName,
|
|
1102
|
+
connectionFailedEventName,
|
|
1103
|
+
blockReconnect,
|
|
1104
|
+
} = connection;
|
|
1105
|
+
if (blockReconnect) {
|
|
1091
1106
|
debug('rabbit: block reconnect');
|
|
1092
1107
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1093
1108
|
// @ts-ignore
|
|
1094
1109
|
return resolve();
|
|
1095
1110
|
}
|
|
1096
|
-
if (
|
|
1097
|
-
if (this.options?.disableReconnect ||
|
|
1111
|
+
if (connectionLocal !== null) {
|
|
1112
|
+
if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
|
|
1098
1113
|
debug('rabbit: connection - is connected');
|
|
1099
1114
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1100
1115
|
// @ts-ignore
|
|
1101
|
-
return resolve(
|
|
1116
|
+
return resolve(connectionLocal);
|
|
1102
1117
|
}
|
|
1103
1118
|
debug('rabbit: connection - reconnecting');
|
|
1104
1119
|
}
|
|
1105
|
-
if (
|
|
1120
|
+
if (creatingConnection) {
|
|
1106
1121
|
debug('rabbit: creating connection emi');
|
|
1107
|
-
this.oldEm.once(
|
|
1108
|
-
this.oldEm.once(
|
|
1122
|
+
this.oldEm.once(connectionCreatedEventName, resolve);
|
|
1123
|
+
this.oldEm.once(connectionFailedEventName, reject);
|
|
1109
1124
|
return;
|
|
1110
1125
|
}
|
|
1111
|
-
|
|
1126
|
+
connection.creatingConnection = true;
|
|
1112
1127
|
let isResolved = false;
|
|
1113
1128
|
|
|
1114
1129
|
// It is import to use it as a function and not as a variable
|
|
@@ -1125,47 +1140,47 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1125
1140
|
};
|
|
1126
1141
|
|
|
1127
1142
|
const defaultUrls = findServers();
|
|
1128
|
-
const
|
|
1143
|
+
const newConnection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
1129
1144
|
findServers,
|
|
1130
1145
|
});
|
|
1131
1146
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1147
|
+
connection.connection = newConnection;
|
|
1148
|
+
newConnection.on('error', (err) => {
|
|
1134
1149
|
logger.error('rabbit: connection error', { err });
|
|
1135
1150
|
if (!isResolved) {
|
|
1136
1151
|
isResolved = true;
|
|
1137
1152
|
reject(err);
|
|
1138
|
-
this.oldEm.emit(
|
|
1153
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1139
1154
|
}
|
|
1140
1155
|
});
|
|
1141
1156
|
|
|
1142
|
-
|
|
1157
|
+
newConnection.on('connectFailed', (err) => {
|
|
1143
1158
|
this.oldConsumersTags = [];
|
|
1144
1159
|
logger.error('rabbit: connection connectFailed', { err });
|
|
1145
1160
|
if (!isResolved) {
|
|
1146
1161
|
isResolved = true;
|
|
1147
1162
|
reject(err);
|
|
1148
|
-
this.oldEm.emit(
|
|
1163
|
+
this.oldEm.emit(connectionFailedEventName, err);
|
|
1149
1164
|
}
|
|
1150
1165
|
});
|
|
1151
1166
|
|
|
1152
|
-
|
|
1167
|
+
newConnection.on('disconnect', ({ err }) => {
|
|
1153
1168
|
this.oldConsumersTags = [];
|
|
1154
1169
|
debug('rabbit: connection closed');
|
|
1155
1170
|
if (this.options?.disableReconnect) {
|
|
1156
1171
|
logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
1157
|
-
|
|
1172
|
+
connection.blockReconnect = true;
|
|
1158
1173
|
} else {
|
|
1159
1174
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
1160
1175
|
}
|
|
1161
1176
|
});
|
|
1162
1177
|
|
|
1163
|
-
|
|
1178
|
+
newConnection.once('connect', async () => {
|
|
1164
1179
|
debug('rabbit: connection established');
|
|
1165
|
-
|
|
1166
|
-
this.oldEm.emit(
|
|
1180
|
+
connection.creatingConnection = false;
|
|
1181
|
+
this.oldEm.emit(connectionCreatedEventName, connection);
|
|
1167
1182
|
isResolved = true;
|
|
1168
|
-
resolve(
|
|
1183
|
+
resolve(newConnection);
|
|
1169
1184
|
});
|
|
1170
1185
|
});
|
|
1171
1186
|
}
|
|
@@ -1199,6 +1214,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1199
1214
|
|
|
1200
1215
|
async setupQueueOld(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
1201
1216
|
let queue: Replies.AssertQueue;
|
|
1217
|
+
const connection = this.oldPublishConnection;
|
|
1202
1218
|
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
1203
1219
|
const localeOptions = {
|
|
1204
1220
|
...options,
|
|
@@ -1210,7 +1226,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1210
1226
|
},
|
|
1211
1227
|
};
|
|
1212
1228
|
try {
|
|
1213
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1229
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1214
1230
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
1215
1231
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
1216
1232
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -1219,8 +1235,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1219
1235
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
1220
1236
|
if (!this.options?.dontRetryAssert) {
|
|
1221
1237
|
debug('retrying assertQueue', { queueName });
|
|
1222
|
-
const channel = await this.assertChannelOld({ force: true });
|
|
1223
|
-
await this.deleteQueueOld(queueName);
|
|
1238
|
+
const channel = await this.assertChannelOld({ force: true, connection });
|
|
1239
|
+
await this.deleteQueueOld(queueName, connection);
|
|
1224
1240
|
|
|
1225
1241
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
1226
1242
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
@@ -1235,19 +1251,22 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1235
1251
|
return queue;
|
|
1236
1252
|
}
|
|
1237
1253
|
|
|
1238
|
-
async assertChannelOld({ force = false }
|
|
1254
|
+
async assertChannelOld({ force = false, connection }: assertChannelOpts): Promise<ChannelWrapper> {
|
|
1239
1255
|
if (!this.oldPublishChannelSetupPromise) {
|
|
1240
1256
|
this.oldPublishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
1241
|
-
if (this.
|
|
1242
|
-
return resolve(this.
|
|
1257
|
+
if (this.oldPublishChannel && !force) {
|
|
1258
|
+
return resolve(this.oldPublishChannel);
|
|
1243
1259
|
}
|
|
1244
1260
|
|
|
1245
1261
|
try {
|
|
1246
|
-
const channel = await this.getNewChannelOld({});
|
|
1262
|
+
const channel = await this.getNewChannelOld({ connection });
|
|
1247
1263
|
channel.on('error', (err) => {
|
|
1248
1264
|
logger.error('rabbit: channel error', { err });
|
|
1249
1265
|
});
|
|
1250
|
-
this.
|
|
1266
|
+
if (this.oldPublishConnection === connection) {
|
|
1267
|
+
debug('rabbit: a new channel assigned to the oldPublishChannel', { connection });
|
|
1268
|
+
this.oldPublishChannel = channel;
|
|
1269
|
+
}
|
|
1251
1270
|
resolve(channel);
|
|
1252
1271
|
} catch (e) {
|
|
1253
1272
|
reject(e);
|
|
@@ -1257,17 +1276,17 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
1257
1276
|
return this.oldPublishChannelSetupPromise;
|
|
1258
1277
|
}
|
|
1259
1278
|
|
|
1260
|
-
private async deleteQueueOld(queue: string) {
|
|
1279
|
+
private async deleteQueueOld(queue: string, connection: ConnectionData) {
|
|
1261
1280
|
RabbitMq.validateName('queue', queue);
|
|
1262
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1281
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1263
1282
|
logger.info('rabbit: deleting queue', { queue });
|
|
1264
1283
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
1265
1284
|
debug('queue deleted', deleteQueueRes);
|
|
1266
1285
|
return deleteQueueRes;
|
|
1267
1286
|
}
|
|
1268
1287
|
|
|
1269
|
-
async assertExchangeOld(exchangeName: string,
|
|
1270
|
-
const channel: ChannelWrapper = await this.assertChannelOld();
|
|
1288
|
+
async assertExchangeOld(exchangeName: string, connection: ConnectionData) {
|
|
1289
|
+
const channel: ChannelWrapper = await this.assertChannelOld({ connection });
|
|
1271
1290
|
|
|
1272
1291
|
if (this.oldExchanges[exchangeName]) {
|
|
1273
1292
|
delete this.oldAssertExchangePromises[exchangeName];
|