@autofleet/rabbit 3.2.26-beta.4 → 3.3.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/coverage/clover.xml +7 -0
- package/coverage/coverage-final.json +1 -0
- package/coverage/lcov-report/base.css +212 -0
- package/coverage/lcov-report/index.html +60 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +1 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +158 -0
- package/coverage/lcov.info +0 -0
- package/dist/index.d.ts +12 -18
- package/dist/index.js +107 -200
- package/dist/lib/consts.d.ts +2 -5
- package/dist/lib/consts.js +3 -7
- package/dist/lib/types.d.ts +0 -10
- package/dist/lib/utils.d.ts +2 -2
- package/package.json +2 -5
- package/src/index.ts +132 -247
- package/src/lib/consts.ts +2 -6
- package/src/lib/types.ts +0 -12
- package/src/lib/utils.ts +2 -6
- package/dist/lib/celery.d.ts +0 -9
- package/dist/lib/celery.js +0 -54
- package/src/lib/celery.ts +0 -89
package/src/index.ts
CHANGED
|
@@ -19,8 +19,8 @@ import RabbitError from './lib/rabbitError';
|
|
|
19
19
|
import getRedisInstance, { RedisConfig } from './lib/redis';
|
|
20
20
|
import { assertExchangeFanout, rand, wrapSetImmediate } from './lib/utils';
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
CONNECTION_CREATED_CONST,
|
|
23
|
+
CONNECTION_FAILED_CONST,
|
|
24
24
|
DEFAULT_LOCK_TIMEOUT,
|
|
25
25
|
DEFAULT_OPTIONS,
|
|
26
26
|
RETRY_HEADER,
|
|
@@ -35,17 +35,14 @@ import {
|
|
|
35
35
|
CustomMessageHeaders,
|
|
36
36
|
QueuesCache,
|
|
37
37
|
RedisLockType,
|
|
38
|
-
ExchangesCache,
|
|
39
|
-
CONSUMER_DEFAULT_OPTIONS,
|
|
40
|
-
QueueSetupPromisesDictionary,
|
|
41
|
-
AssertExchangePromisesDictionary,
|
|
42
|
-
ConnectionData,
|
|
38
|
+
ExchangesCache, CONSUMER_DEFAULT_OPTIONS, QueueSetupPromisesDictionary,
|
|
43
39
|
} from './lib/types';
|
|
44
40
|
|
|
45
41
|
// const debug = nodeDebug('af-rabbitmq')
|
|
46
42
|
const debug = logger.debug.bind(logger);
|
|
47
43
|
|
|
48
44
|
const PUBLISH_TIMEOUT = 1000 * 10;
|
|
45
|
+
|
|
49
46
|
export interface IAfRabbitMq {
|
|
50
47
|
ack: any;
|
|
51
48
|
nack: any;
|
|
@@ -79,19 +76,21 @@ export interface AfRabbitOptions {
|
|
|
79
76
|
dontRetryAssert?: boolean;
|
|
80
77
|
|
|
81
78
|
rabbitHost?: string;
|
|
79
|
+
|
|
80
|
+
serviceName: string;
|
|
81
|
+
|
|
82
|
+
podIp?: string;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
type newChannelOpts = {
|
|
85
86
|
name?: string;
|
|
86
87
|
onClose?: null | ((args: any | null) => void);
|
|
87
88
|
options?: CreateChannelOpts | undefined;
|
|
88
|
-
connectionPurpose?: ConnectionPurpose,
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
type assertChannelOpts = {
|
|
92
92
|
channelName?: string;
|
|
93
93
|
force?: boolean;
|
|
94
|
-
connectionPurpose?: ConnectionPurpose;
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
type AfConsumer = {
|
|
@@ -103,7 +102,7 @@ type AfConsumer = {
|
|
|
103
102
|
const HEARTBEAT = '60';
|
|
104
103
|
|
|
105
104
|
class RabbitMq implements IAfRabbitMq {
|
|
106
|
-
static parseMsg(msg: any): any {
|
|
105
|
+
static parseMsg(msg: any) : any {
|
|
107
106
|
let { content } = msg;
|
|
108
107
|
content = content.toString();
|
|
109
108
|
|
|
@@ -144,27 +143,24 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
144
143
|
|
|
145
144
|
RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
publishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
146
|
+
channel: ChannelWrapper | null;
|
|
150
147
|
|
|
151
|
-
blockReconnect: boolean | null | undefined
|
|
148
|
+
blockReconnect: boolean | null | undefined
|
|
152
149
|
|
|
153
|
-
|
|
154
|
-
[ConnectionPurpose.Consume]: ConnectionData;
|
|
155
|
-
[ConnectionPurpose.Publish]: ConnectionData;
|
|
156
|
-
};
|
|
150
|
+
connection: AmqpConnectionManager | null | undefined
|
|
157
151
|
|
|
158
152
|
em: EventEmitter;
|
|
159
153
|
|
|
154
|
+
podId: string;
|
|
155
|
+
|
|
156
|
+
creatingConnection: boolean;
|
|
157
|
+
|
|
160
158
|
exchanges: ExchangesCache;
|
|
161
159
|
|
|
162
160
|
queues: QueuesCache;
|
|
163
161
|
|
|
164
162
|
queueSetupPromises: QueueSetupPromisesDictionary;
|
|
165
163
|
|
|
166
|
-
assertExchangePromises: AssertExchangePromisesDictionary;
|
|
167
|
-
|
|
168
164
|
options: AfRabbitOptions | undefined;
|
|
169
165
|
|
|
170
166
|
redisClient: any;
|
|
@@ -178,28 +174,15 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
178
174
|
|
|
179
175
|
constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig) {
|
|
180
176
|
this.em = new EventEmitter();
|
|
181
|
-
this.
|
|
182
|
-
this.
|
|
183
|
-
this.
|
|
184
|
-
[ConnectionPurpose.Consume]: {
|
|
185
|
-
connection: null,
|
|
186
|
-
creatingConnection: false,
|
|
187
|
-
connectionCreatedEventName: 'consumeConnectionCreated',
|
|
188
|
-
connectionFailedEventName: 'consumeConnectionFailed',
|
|
189
|
-
},
|
|
190
|
-
[ConnectionPurpose.Publish]: {
|
|
191
|
-
connection: null,
|
|
192
|
-
creatingConnection: false,
|
|
193
|
-
connectionCreatedEventName: 'publishConnectionCreated',
|
|
194
|
-
connectionFailedEventName: 'publishConnectionFailed',
|
|
195
|
-
},
|
|
196
|
-
};
|
|
177
|
+
this.channel = null;
|
|
178
|
+
this.connection = null;
|
|
179
|
+
this.creatingConnection = false;
|
|
197
180
|
this.exchanges = {};
|
|
198
181
|
this.queues = {};
|
|
199
182
|
this.queueSetupPromises = {};
|
|
200
|
-
this.assertExchangePromises = {};
|
|
201
183
|
this.consumers = [];
|
|
202
184
|
this.options = options;
|
|
185
|
+
this.podId = `${options?.serviceName}${options?.podIp ? `-${options.podIp}` : ''}`;
|
|
203
186
|
this.redisClient = redisConfig && getRedisInstance(redisConfig);
|
|
204
187
|
if (this.redisClient) {
|
|
205
188
|
this.redisLock = promisify(RedisLock(this.redisClient)) as RedisLockType;
|
|
@@ -230,7 +213,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
230
213
|
return false;
|
|
231
214
|
}
|
|
232
215
|
|
|
233
|
-
public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage): Promise<any> => {
|
|
216
|
+
public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
|
|
234
217
|
if (msg) {
|
|
235
218
|
debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
|
|
236
219
|
await channel.ack(msg);
|
|
@@ -256,8 +239,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
256
239
|
userMsg: ConsumeMessageOrNull,
|
|
257
240
|
{
|
|
258
241
|
skipRetry = false,
|
|
259
|
-
}: NackOptions = {},
|
|
260
|
-
): Promise<any> => {
|
|
242
|
+
}: NackOptions = { },
|
|
243
|
+
) : Promise<any> => {
|
|
261
244
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
262
245
|
if (channel && msg) {
|
|
263
246
|
if (
|
|
@@ -291,36 +274,30 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
291
274
|
}
|
|
292
275
|
}
|
|
293
276
|
|
|
294
|
-
async getConnection(
|
|
295
|
-
return new Promise<AmqpConnectionManager
|
|
296
|
-
const {
|
|
297
|
-
connection,
|
|
298
|
-
creatingConnection,
|
|
299
|
-
connectionCreatedEventName,
|
|
300
|
-
connectionFailedEventName,
|
|
301
|
-
} = this.connectionsMap[connectionPurpose];
|
|
277
|
+
async getConnection() {
|
|
278
|
+
return new Promise<AmqpConnectionManager>(async (resolve, reject) => {
|
|
302
279
|
if (this.blockReconnect) {
|
|
303
280
|
debug('rabbit: block reconnect');
|
|
304
281
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
305
282
|
// @ts-ignore
|
|
306
283
|
return resolve();
|
|
307
284
|
}
|
|
308
|
-
if (connection !== null) {
|
|
309
|
-
if (this.options?.disableReconnect || connection?.isConnected()) {
|
|
285
|
+
if (this.connection !== null) {
|
|
286
|
+
if (this.options?.disableReconnect || this.connection?.isConnected()) {
|
|
310
287
|
debug('rabbit: connection - is connected');
|
|
311
288
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
312
289
|
// @ts-ignore
|
|
313
|
-
return resolve(connection);
|
|
290
|
+
return resolve(this.connection);
|
|
314
291
|
}
|
|
315
292
|
debug('rabbit: connection - reconnecting');
|
|
316
293
|
}
|
|
317
|
-
if (creatingConnection) {
|
|
294
|
+
if (this.creatingConnection) {
|
|
318
295
|
debug('rabbit: creating connection emi');
|
|
319
|
-
this.em.once(
|
|
320
|
-
this.em.once(
|
|
296
|
+
this.em.once(CONNECTION_CREATED_CONST, resolve);
|
|
297
|
+
this.em.once(CONNECTION_FAILED_CONST, reject);
|
|
321
298
|
return;
|
|
322
299
|
}
|
|
323
|
-
this.
|
|
300
|
+
this.creatingConnection = true;
|
|
324
301
|
let isResolved = false;
|
|
325
302
|
|
|
326
303
|
// It is import to use it as a function and not as a variable
|
|
@@ -337,33 +314,31 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
337
314
|
};
|
|
338
315
|
|
|
339
316
|
const defaultUrls = findServers();
|
|
340
|
-
const
|
|
317
|
+
const connection: AmqpConnectionManager = await connect(defaultUrls, {
|
|
341
318
|
findServers,
|
|
342
319
|
});
|
|
343
320
|
|
|
344
|
-
this.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
newConnection.on('error', (err) => {
|
|
321
|
+
this.connection = connection;
|
|
322
|
+
this.connection.on('error', (err) => {
|
|
348
323
|
logger.error('rabbit: connection error', { err });
|
|
349
324
|
if (!isResolved) {
|
|
350
325
|
isResolved = true;
|
|
351
326
|
reject(err);
|
|
352
|
-
this.em.emit(
|
|
327
|
+
this.em.emit(CONNECTION_FAILED_CONST, err);
|
|
353
328
|
}
|
|
354
329
|
});
|
|
355
330
|
|
|
356
|
-
|
|
331
|
+
this.connection.on('connectFailed', (err) => {
|
|
357
332
|
this.consumersTags = [];
|
|
358
333
|
logger.error('rabbit: connection connectFailed', { err });
|
|
359
334
|
if (!isResolved) {
|
|
360
335
|
isResolved = true;
|
|
361
336
|
reject(err);
|
|
362
|
-
this.em.emit(
|
|
337
|
+
this.em.emit(CONNECTION_FAILED_CONST, err);
|
|
363
338
|
}
|
|
364
339
|
});
|
|
365
340
|
|
|
366
|
-
|
|
341
|
+
this.connection.on('disconnect', ({ err }) => {
|
|
367
342
|
this.consumersTags = [];
|
|
368
343
|
debug('rabbit: connection closed');
|
|
369
344
|
if (this.options?.disableReconnect) {
|
|
@@ -373,29 +348,25 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
373
348
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
374
349
|
}
|
|
375
350
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
this.
|
|
351
|
+
this.connection.once('connect', async () => {
|
|
352
|
+
debug('rabbit: connection established');
|
|
353
|
+
this.creatingConnection = false;
|
|
354
|
+
this.em.emit(CONNECTION_CREATED_CONST, connection);
|
|
379
355
|
isResolved = true;
|
|
380
|
-
resolve(
|
|
356
|
+
resolve(connection);
|
|
381
357
|
});
|
|
382
358
|
});
|
|
383
359
|
}
|
|
384
360
|
|
|
385
|
-
async getNewChannel({
|
|
386
|
-
|
|
387
|
-
}: newChannelOpts): Promise<ChannelWrapper> {
|
|
388
|
-
let connection!: AmqpConnectionManager | undefined | null;
|
|
361
|
+
async getNewChannel({ name = rand().toString(), onClose = null, options = {} }: newChannelOpts = {}) {
|
|
362
|
+
let connection!: AmqpConnectionManager;
|
|
389
363
|
try {
|
|
390
|
-
connection = await this.getConnection(
|
|
364
|
+
connection = await this.getConnection();
|
|
391
365
|
} catch (e) {
|
|
392
366
|
logger.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
393
367
|
throw e;
|
|
394
368
|
}
|
|
395
|
-
|
|
396
|
-
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
397
|
-
}
|
|
398
|
-
const channel = connection.createChannel({ ...options });
|
|
369
|
+
const channel = connection.createChannel({ ...options, name });
|
|
399
370
|
once(channel, 'close').then((args) => {
|
|
400
371
|
logger.error(`rabbit: channel ${name} closed`);
|
|
401
372
|
onClose?.(args);
|
|
@@ -410,62 +381,48 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
410
381
|
}
|
|
411
382
|
}
|
|
412
383
|
|
|
413
|
-
async assertChannel({ force = false
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
return resolve(this.publishChannel);
|
|
419
|
-
}
|
|
384
|
+
async assertChannel({ force = false } : assertChannelOpts = {}): Promise<ChannelWrapper> {
|
|
385
|
+
return new Promise<ChannelWrapper>(async (resolve, reject) => {
|
|
386
|
+
if (this.channel && !force) {
|
|
387
|
+
return resolve(this.channel);
|
|
388
|
+
}
|
|
420
389
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
reject(e);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
return this.publishChannelSetupPromise;
|
|
390
|
+
try {
|
|
391
|
+
const channel = await this.getNewChannel({});
|
|
392
|
+
channel.on('error', (err) => {
|
|
393
|
+
logger.error('rabbit: channel error', { err });
|
|
394
|
+
});
|
|
395
|
+
this.channel = channel;
|
|
396
|
+
resolve(channel);
|
|
397
|
+
} catch (e) {
|
|
398
|
+
reject(e);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
437
401
|
}
|
|
438
402
|
|
|
439
|
-
async assertExchange(exchangeName: string, options
|
|
440
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
403
|
+
async assertExchange(exchangeName: string, options?: any) {
|
|
404
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
441
405
|
if (this.exchanges[exchangeName]) {
|
|
442
|
-
delete this.assertExchangePromises[exchangeName];
|
|
443
406
|
return this.exchanges[exchangeName];
|
|
444
407
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
this.assertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
|
|
451
|
-
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
452
|
-
return this.exchanges[exchangeName];
|
|
408
|
+
const exchange = await assertExchangeFanout(channel, exchangeName);
|
|
409
|
+
this.exchanges[exchangeName] = exchange;
|
|
410
|
+
return exchange;
|
|
453
411
|
}
|
|
454
412
|
|
|
455
|
-
async getQueueLength(queue: string
|
|
413
|
+
async getQueueLength(queue: string) {
|
|
456
414
|
RabbitMq.validateName('queue', queue);
|
|
457
|
-
const {
|
|
458
|
-
|
|
459
|
-
if (!publishChannel) {
|
|
415
|
+
const { channel } = this;
|
|
416
|
+
if (!channel) {
|
|
460
417
|
throw new Error('channel is not defined');
|
|
461
418
|
}
|
|
462
|
-
debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
|
|
463
|
-
return
|
|
419
|
+
debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
|
|
420
|
+
return channel?.checkQueue(queue);
|
|
464
421
|
}
|
|
465
422
|
|
|
466
|
-
private async deleteQueue(queue: string
|
|
423
|
+
private async deleteQueue(queue: string) {
|
|
467
424
|
RabbitMq.validateName('queue', queue);
|
|
468
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
425
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
469
426
|
logger.info('rabbit: deleting queue', { queue });
|
|
470
427
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
471
428
|
debug('queue deleted', deleteQueueRes);
|
|
@@ -473,67 +430,40 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
473
430
|
}
|
|
474
431
|
|
|
475
432
|
async bindQueue(queue: string, exchange: string) {
|
|
476
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
433
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
477
434
|
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
478
435
|
return channel.bindQueue(queue, exchange, '');
|
|
479
436
|
}
|
|
480
437
|
|
|
481
438
|
async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
482
439
|
let queue: Replies.AssertQueue;
|
|
483
|
-
const connectionPurpose = ConnectionPurpose.Publish;
|
|
484
|
-
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
485
|
-
const localeOptions = {
|
|
486
|
-
...options,
|
|
487
|
-
durable: true,
|
|
488
|
-
arguments: {
|
|
489
|
-
...options?.arguments,
|
|
490
|
-
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
491
|
-
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
492
|
-
},
|
|
493
|
-
};
|
|
494
440
|
try {
|
|
495
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
441
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
496
442
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
497
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName,
|
|
443
|
+
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
498
444
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
499
|
-
queue = await channel.assertQueue(queueName,
|
|
445
|
+
queue = await channel.assertQueue(queueName, options);
|
|
500
446
|
} catch (e) {
|
|
501
447
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
502
448
|
if (!this.options?.dontRetryAssert) {
|
|
503
449
|
debug('retrying assertQueue', { queueName });
|
|
504
|
-
const channel = await this.assertChannel({ force: true
|
|
505
|
-
await this.deleteQueue(queueName
|
|
450
|
+
const channel = await this.assertChannel({ force: true });
|
|
451
|
+
await this.deleteQueue(queueName);
|
|
506
452
|
|
|
507
453
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
508
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName,
|
|
454
|
+
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
509
455
|
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
510
|
-
queue = await channel.assertQueue(queueName,
|
|
456
|
+
queue = await channel.assertQueue(queueName, options);
|
|
511
457
|
} else {
|
|
512
458
|
throw e;
|
|
513
459
|
}
|
|
514
460
|
}
|
|
515
461
|
|
|
516
|
-
this.queues[queueName] =
|
|
462
|
+
this.queues[queueName] = queueName;
|
|
517
463
|
return queue;
|
|
518
464
|
}
|
|
519
465
|
|
|
520
|
-
static shouldUseQuorum(queueName: string): boolean {
|
|
521
|
-
const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
|
|
522
|
-
|
|
523
|
-
if (envQuorumQueuesWhitelist === '*') {
|
|
524
|
-
return true;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
if (envQuorumQueuesWhitelist) {
|
|
528
|
-
const whitelist = envQuorumQueuesWhitelist.split(',');
|
|
529
|
-
return whitelist.includes(queueName);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
466
|
async assertQueue(queueName: string, options?: Options.AssertQueue) {
|
|
536
|
-
debug('rabbit: start assert queue', { queueName });
|
|
537
467
|
RabbitMq.validateName('queue', queueName);
|
|
538
468
|
if (this.queues[queueName]) {
|
|
539
469
|
delete this.queueSetupPromises[queueName];
|
|
@@ -545,12 +475,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
545
475
|
}
|
|
546
476
|
|
|
547
477
|
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
548
|
-
debug('rabbit: done assert queue', { queueName });
|
|
549
478
|
return this.queueSetupPromises[queueName];
|
|
550
479
|
}
|
|
551
480
|
|
|
552
481
|
private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
|
|
553
|
-
const isConsumerExist:
|
|
482
|
+
const isConsumerExist :boolean = this.consumers.some((consumer) => consumer.queue === queue);
|
|
554
483
|
if (!isConsumerExist) {
|
|
555
484
|
logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
556
485
|
this.consumers.push({
|
|
@@ -599,10 +528,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
599
528
|
}
|
|
600
529
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
601
530
|
}
|
|
602
|
-
const channel = await this.getNewChannel({
|
|
531
|
+
const channel = await this.getNewChannel({ name: `${this.podId}_queue_${queue}` });
|
|
603
532
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
604
|
-
|
|
605
|
-
await confirmChannel.prefetch(limit,
|
|
533
|
+
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
534
|
+
await confirmChannel.prefetch(limit, true);
|
|
606
535
|
const { consumerTag } = await confirmChannel.consume(
|
|
607
536
|
queue,
|
|
608
537
|
async (msg: ConsumeMessageOrNull) => {
|
|
@@ -612,7 +541,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
612
541
|
|
|
613
542
|
const traceId = msg.properties.headers[TRACING_HEADER];
|
|
614
543
|
const userId = msg.properties.headers[USER_TRACING_HEADER];
|
|
615
|
-
const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
|
|
616
544
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
617
545
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
618
546
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -638,10 +566,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
638
566
|
}
|
|
639
567
|
|
|
640
568
|
if (auditContext) {
|
|
641
|
-
await auditContext(queue
|
|
642
|
-
userId,
|
|
643
|
-
automationId,
|
|
644
|
-
});
|
|
569
|
+
await auditContext(queue);
|
|
645
570
|
}
|
|
646
571
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
647
572
|
if (!shouldConsume) {
|
|
@@ -689,19 +614,19 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
689
614
|
});
|
|
690
615
|
}
|
|
691
616
|
|
|
692
|
-
async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
|
|
617
|
+
async consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions) : Promise<any> {
|
|
693
618
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
694
619
|
RabbitMq.validateName('exchange', exchange);
|
|
695
620
|
RabbitMq.validateName('queue', queue);
|
|
696
621
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
697
622
|
await this.saveConsumer(queue, callback, options);
|
|
698
|
-
const channel: ChannelWrapper = await this.getNewChannel({ name:
|
|
623
|
+
const channel: ChannelWrapper = await this.getNewChannel({ name: `${this.podId}_exchange_${exchange}_queue_${queue}` });
|
|
699
624
|
|
|
700
625
|
return channel.addSetup(async (c: ConfirmChannel) => {
|
|
701
626
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
702
627
|
await c.assertQueue(queue);
|
|
703
628
|
this.exchanges[exchange] = assertExchange;
|
|
704
|
-
await c.prefetch(limit,
|
|
629
|
+
await c.prefetch(limit, true);
|
|
705
630
|
return Promise.all([
|
|
706
631
|
c.bindQueue(queue, exchange, ''),
|
|
707
632
|
this.consume(
|
|
@@ -713,12 +638,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
713
638
|
});
|
|
714
639
|
}
|
|
715
640
|
|
|
716
|
-
async publish(exchange: string, content: any, customHeaders?: any): Promise<boolean> {
|
|
717
|
-
debug('rabbit: start publish msg');
|
|
641
|
+
async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
|
|
718
642
|
return wrapSetImmediate(async () => {
|
|
719
643
|
RabbitMq.validateName('exchange', exchange);
|
|
720
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
721
|
-
await this.assertExchange(exchange
|
|
644
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
645
|
+
await this.assertExchange(exchange);
|
|
722
646
|
await channel.publish(exchange, '',
|
|
723
647
|
Buffer.from(JSON.stringify(content)),
|
|
724
648
|
RabbitMq.getPublishOptions(customHeaders));
|
|
@@ -730,86 +654,51 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
730
654
|
content: any,
|
|
731
655
|
options?: any,
|
|
732
656
|
customHeaders?: any,
|
|
657
|
+
isBlocking?: boolean,
|
|
733
658
|
): Promise<boolean | undefined> {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
659
|
+
const callback = async (): Promise<boolean | undefined> => {
|
|
660
|
+
try {
|
|
661
|
+
RabbitMq.validateName('queue', queue);
|
|
662
|
+
await this.assertChannel();
|
|
663
|
+
await this.assertQueue(queue, options);
|
|
664
|
+
const res = await this.channel?.sendToQueue(queue,
|
|
665
|
+
Buffer.from(JSON.stringify(content)),
|
|
666
|
+
RabbitMq.getPublishOptions(customHeaders));
|
|
667
|
+
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
668
|
+
return res;
|
|
669
|
+
} catch (e) {
|
|
670
|
+
logger.error(`rabbit: failed to send to queue ${queue}`, { e });
|
|
671
|
+
throw e;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
if (isBlocking) {
|
|
675
|
+
return callback();
|
|
739
676
|
}
|
|
677
|
+
return wrapSetImmediate(callback);
|
|
678
|
+
}
|
|
740
679
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
logger.error(
|
|
746
|
-
|
|
680
|
+
async isConnected() : Promise<boolean> {
|
|
681
|
+
const connection = await this.getConnection();
|
|
682
|
+
const isConnected = connection.isConnected();
|
|
683
|
+
if (!isConnected) {
|
|
684
|
+
logger.error('rabbit: isConnected - false');
|
|
685
|
+
return false;
|
|
747
686
|
}
|
|
748
|
-
|
|
687
|
+
const channel: any = await this.assertChannel();
|
|
749
688
|
try {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
return res;
|
|
689
|
+
await Promise.all([
|
|
690
|
+
channel.waitForConnect(),
|
|
691
|
+
...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
692
|
+
]);
|
|
755
693
|
} catch (e) {
|
|
756
|
-
logger.error(
|
|
757
|
-
|
|
694
|
+
logger.error('rabbit: isConnected - false');
|
|
695
|
+
return false;
|
|
758
696
|
}
|
|
697
|
+
logger.info('rabbit: isConnected - true');
|
|
698
|
+
return true;
|
|
759
699
|
}
|
|
760
700
|
|
|
761
|
-
|
|
762
|
-
// const isConnected = connection.isConnected();
|
|
763
|
-
// if (!isConnected) {
|
|
764
|
-
// logger.error('rabbit: isConnected - false');
|
|
765
|
-
// return false;
|
|
766
|
-
// }
|
|
767
|
-
// const channel: any = await this.assertChannel();
|
|
768
|
-
// try {
|
|
769
|
-
// await Promise.all([
|
|
770
|
-
// channel.waitForConnect(),
|
|
771
|
-
// ...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
772
|
-
// ]);
|
|
773
|
-
// } catch (e) {
|
|
774
|
-
// logger.error('rabbit: isConnected - false');
|
|
775
|
-
// return false;
|
|
776
|
-
// }
|
|
777
|
-
// logger.info('rabbit: isConnected - true');
|
|
778
|
-
// return true;
|
|
779
|
-
|
|
780
|
-
async isConnected(): Promise<boolean> {
|
|
781
|
-
debug('rabbit: start is connected');
|
|
782
|
-
const isEachConnectionConnected = await Promise.all(
|
|
783
|
-
Object.entries(this.connectionsMap).map(async ([connectionPurpose, connectionData]) => {
|
|
784
|
-
const { connection } = connectionData;
|
|
785
|
-
if (connectionPurpose === ConnectionPurpose.Publish && connection) {
|
|
786
|
-
const channel: any = await this.assertChannel({ connectionPurpose: connectionPurpose as ConnectionPurpose });
|
|
787
|
-
try {
|
|
788
|
-
await Promise.all([
|
|
789
|
-
channel.waitForConnect(),
|
|
790
|
-
...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
791
|
-
]);
|
|
792
|
-
} catch (e) {
|
|
793
|
-
logger.error('rabbit: isConnected - false');
|
|
794
|
-
return false;
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
if (connection) {
|
|
799
|
-
const isConnected = connection?.isConnected();
|
|
800
|
-
if (!isConnected) {
|
|
801
|
-
logger.error('rabbit: isConnected - false', { connectionPurpose });
|
|
802
|
-
return false;
|
|
803
|
-
}
|
|
804
|
-
logger.info('rabbit: isConnected - true', { connectionPurpose });
|
|
805
|
-
}
|
|
806
|
-
return true;
|
|
807
|
-
}),
|
|
808
|
-
);
|
|
809
|
-
return isEachConnectionConnected.every((isConnected) => isConnected === true);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
async gracefulShutdown(signal: string): Promise<void> {
|
|
701
|
+
async gracefulShutdown(signal: string) : Promise<void> {
|
|
813
702
|
const tagsNumber = this.consumersTags.length;
|
|
814
703
|
logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
815
704
|
const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
@@ -826,7 +715,3 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
826
715
|
}
|
|
827
716
|
|
|
828
717
|
export default RabbitMq;
|
|
829
|
-
|
|
830
|
-
export {
|
|
831
|
-
sendCeleryTaskViaHttp,
|
|
832
|
-
} from './lib/celery';
|
package/src/lib/consts.ts
CHANGED
|
@@ -3,9 +3,10 @@ export const DEFAULT_LOCK_TIMEOUT = 1000 * 5;
|
|
|
3
3
|
export const RETRY_HEADER = 'x-retry-count';
|
|
4
4
|
export const TRACING_HEADER = 'x-trace-id';
|
|
5
5
|
export const USER_TRACING_HEADER = 'x-af-user-id';
|
|
6
|
-
export const AUTOMATION_ID_HEADER = 'x-af-automation-id';
|
|
7
6
|
export const USER_OBJECT = 'userObject';
|
|
8
7
|
export const DEFAULT_USE_CONSUME_WITH_LOCK = false;
|
|
8
|
+
export const CONNECTION_CREATED_CONST = 'connectionCreated';
|
|
9
|
+
export const CONNECTION_FAILED_CONST = 'connectionFailed';
|
|
9
10
|
export const DEFAULT_OPTIONS = {
|
|
10
11
|
limit: 1,
|
|
11
12
|
retries: 1,
|
|
@@ -15,8 +16,3 @@ export const DEFAULT_OPTIONS = {
|
|
|
15
16
|
auditContext: null,
|
|
16
17
|
enableRabbitTrace: false,
|
|
17
18
|
};
|
|
18
|
-
|
|
19
|
-
export enum ConnectionPurpose {
|
|
20
|
-
Consume = 'consume',
|
|
21
|
-
Publish = 'publish',
|
|
22
|
-
}
|