@autofleet/rabbit 3.2.26-beta.3 → 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 +14 -20
- package/dist/index.js +110 -183
- 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 +135 -228
- 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,66 +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
|
-
async setupQueue(queueName: string,
|
|
438
|
+
async setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
|
|
482
439
|
let queue: Replies.AssertQueue;
|
|
483
|
-
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
484
|
-
const localeOptions = {
|
|
485
|
-
...options,
|
|
486
|
-
durable: true,
|
|
487
|
-
arguments: {
|
|
488
|
-
...options?.arguments,
|
|
489
|
-
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
490
|
-
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
491
|
-
},
|
|
492
|
-
};
|
|
493
440
|
try {
|
|
494
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
441
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
495
442
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
496
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName,
|
|
443
|
+
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
497
444
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
498
|
-
queue = await channel.assertQueue(queueName,
|
|
445
|
+
queue = await channel.assertQueue(queueName, options);
|
|
499
446
|
} catch (e) {
|
|
500
447
|
logger.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
501
448
|
if (!this.options?.dontRetryAssert) {
|
|
502
449
|
debug('retrying assertQueue', { queueName });
|
|
503
|
-
const channel = await this.assertChannel({ force: true
|
|
504
|
-
await this.deleteQueue(queueName
|
|
450
|
+
const channel = await this.assertChannel({ force: true });
|
|
451
|
+
await this.deleteQueue(queueName);
|
|
505
452
|
|
|
506
453
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
507
|
-
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName,
|
|
454
|
+
await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
|
|
508
455
|
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
509
|
-
queue = await channel.assertQueue(queueName,
|
|
456
|
+
queue = await channel.assertQueue(queueName, options);
|
|
510
457
|
} else {
|
|
511
458
|
throw e;
|
|
512
459
|
}
|
|
513
460
|
}
|
|
514
461
|
|
|
515
|
-
this.queues[queueName] =
|
|
462
|
+
this.queues[queueName] = queueName;
|
|
516
463
|
return queue;
|
|
517
464
|
}
|
|
518
465
|
|
|
519
|
-
|
|
520
|
-
const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
|
|
521
|
-
|
|
522
|
-
if (envQuorumQueuesWhitelist === '*') {
|
|
523
|
-
return true;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (envQuorumQueuesWhitelist) {
|
|
527
|
-
const whitelist = envQuorumQueuesWhitelist.split(',');
|
|
528
|
-
return whitelist.includes(queueName);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return false;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
async assertQueue(queueName: string, connectionPurpose: ConnectionPurpose, options?: Options.AssertQueue) {
|
|
535
|
-
debug('rabbit: start assert queue', { connectionPurpose, queueName });
|
|
466
|
+
async assertQueue(queueName: string, options?: Options.AssertQueue) {
|
|
536
467
|
RabbitMq.validateName('queue', queueName);
|
|
537
468
|
if (this.queues[queueName]) {
|
|
538
469
|
delete this.queueSetupPromises[queueName];
|
|
@@ -543,13 +474,12 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
543
474
|
return this.queueSetupPromises[queueName];
|
|
544
475
|
}
|
|
545
476
|
|
|
546
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName,
|
|
547
|
-
debug('rabbit: done assert queue', { connectionPurpose, queueName });
|
|
477
|
+
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
548
478
|
return this.queueSetupPromises[queueName];
|
|
549
479
|
}
|
|
550
480
|
|
|
551
481
|
private saveConsumer(queue: string, callback: CallbackFunction, options: ConsumeOptions | undefined) {
|
|
552
|
-
const isConsumerExist:
|
|
482
|
+
const isConsumerExist :boolean = this.consumers.some((consumer) => consumer.queue === queue);
|
|
553
483
|
if (!isConsumerExist) {
|
|
554
484
|
logger.info(`rabbit: consumer: ${queue} saved in consumer array`);
|
|
555
485
|
this.consumers.push({
|
|
@@ -598,10 +528,10 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
598
528
|
}
|
|
599
529
|
logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
600
530
|
}
|
|
601
|
-
const channel = await this.getNewChannel({
|
|
531
|
+
const channel = await this.getNewChannel({ name: `${this.podId}_queue_${queue}` });
|
|
602
532
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
603
|
-
|
|
604
|
-
await confirmChannel.prefetch(limit,
|
|
533
|
+
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
534
|
+
await confirmChannel.prefetch(limit, true);
|
|
605
535
|
const { consumerTag } = await confirmChannel.consume(
|
|
606
536
|
queue,
|
|
607
537
|
async (msg: ConsumeMessageOrNull) => {
|
|
@@ -611,7 +541,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
611
541
|
|
|
612
542
|
const traceId = msg.properties.headers[TRACING_HEADER];
|
|
613
543
|
const userId = msg.properties.headers[USER_TRACING_HEADER];
|
|
614
|
-
const automationId = msg.properties.headers[AUTOMATION_ID_HEADER];
|
|
615
544
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
616
545
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
617
546
|
const trace = newTrace(traceTypes.RABBIT);
|
|
@@ -637,10 +566,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
637
566
|
}
|
|
638
567
|
|
|
639
568
|
if (auditContext) {
|
|
640
|
-
await auditContext(queue
|
|
641
|
-
userId,
|
|
642
|
-
automationId,
|
|
643
|
-
});
|
|
569
|
+
await auditContext(queue);
|
|
644
570
|
}
|
|
645
571
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
646
572
|
if (!shouldConsume) {
|
|
@@ -688,19 +614,19 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
688
614
|
});
|
|
689
615
|
}
|
|
690
616
|
|
|
691
|
-
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> {
|
|
692
618
|
const optionsWithDefaults = { ...DEFAULT_OPTIONS, ...options };
|
|
693
619
|
RabbitMq.validateName('exchange', exchange);
|
|
694
620
|
RabbitMq.validateName('queue', queue);
|
|
695
621
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
696
622
|
await this.saveConsumer(queue, callback, options);
|
|
697
|
-
const channel: ChannelWrapper = await this.getNewChannel({ name:
|
|
623
|
+
const channel: ChannelWrapper = await this.getNewChannel({ name: `${this.podId}_exchange_${exchange}_queue_${queue}` });
|
|
698
624
|
|
|
699
625
|
return channel.addSetup(async (c: ConfirmChannel) => {
|
|
700
626
|
const assertExchange = await assertExchangeFanout(c, exchange);
|
|
701
627
|
await c.assertQueue(queue);
|
|
702
628
|
this.exchanges[exchange] = assertExchange;
|
|
703
|
-
await c.prefetch(limit,
|
|
629
|
+
await c.prefetch(limit, true);
|
|
704
630
|
return Promise.all([
|
|
705
631
|
c.bindQueue(queue, exchange, ''),
|
|
706
632
|
this.consume(
|
|
@@ -712,12 +638,11 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
712
638
|
});
|
|
713
639
|
}
|
|
714
640
|
|
|
715
|
-
async publish(exchange: string, content: any, customHeaders?: any): Promise<boolean> {
|
|
716
|
-
debug('rabbit: start publish msg');
|
|
641
|
+
async publish(exchange: string, content: any, customHeaders?: any) : Promise<boolean> {
|
|
717
642
|
return wrapSetImmediate(async () => {
|
|
718
643
|
RabbitMq.validateName('exchange', exchange);
|
|
719
|
-
const channel: ChannelWrapper = await this.assertChannel(
|
|
720
|
-
await this.assertExchange(exchange
|
|
644
|
+
const channel: ChannelWrapper = await this.assertChannel();
|
|
645
|
+
await this.assertExchange(exchange);
|
|
721
646
|
await channel.publish(exchange, '',
|
|
722
647
|
Buffer.from(JSON.stringify(content)),
|
|
723
648
|
RabbitMq.getPublishOptions(customHeaders));
|
|
@@ -729,65 +654,51 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
729
654
|
content: any,
|
|
730
655
|
options?: any,
|
|
731
656
|
customHeaders?: any,
|
|
657
|
+
isBlocking?: boolean,
|
|
732
658
|
): Promise<boolean | undefined> {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
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();
|
|
738
676
|
}
|
|
677
|
+
return wrapSetImmediate(callback);
|
|
678
|
+
}
|
|
739
679
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
logger.error(
|
|
745
|
-
|
|
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;
|
|
746
686
|
}
|
|
747
|
-
|
|
687
|
+
const channel: any = await this.assertChannel();
|
|
748
688
|
try {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
return res;
|
|
689
|
+
await Promise.all([
|
|
690
|
+
channel.waitForConnect(),
|
|
691
|
+
...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
692
|
+
]);
|
|
754
693
|
} catch (e) {
|
|
755
|
-
logger.error(
|
|
756
|
-
|
|
694
|
+
logger.error('rabbit: isConnected - false');
|
|
695
|
+
return false;
|
|
757
696
|
}
|
|
697
|
+
logger.info('rabbit: isConnected - true');
|
|
698
|
+
return true;
|
|
758
699
|
}
|
|
759
700
|
|
|
760
|
-
async
|
|
761
|
-
debug('rabbit: start is connected');
|
|
762
|
-
const isEachConnectionConnected = await Promise.all(
|
|
763
|
-
Object.entries(this.connectionsMap).map(async ([connectionPurpose, connectionData]) => {
|
|
764
|
-
if (connectionPurpose === ConnectionPurpose.Publish) {
|
|
765
|
-
const channel: any = await this.assertChannel({ connectionPurpose: connectionPurpose as ConnectionPurpose });
|
|
766
|
-
try {
|
|
767
|
-
await Promise.all([
|
|
768
|
-
channel.waitForConnect(),
|
|
769
|
-
...this.consumers.map((c: AfConsumer) => channel.checkQueue(c.queue)),
|
|
770
|
-
]);
|
|
771
|
-
} catch (e) {
|
|
772
|
-
logger.error('rabbit: isConnected - false');
|
|
773
|
-
return false;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
const { connection } = connectionData;
|
|
777
|
-
debug('rabbit: is connected inside map', { connection, connectionPurpose });
|
|
778
|
-
const isConnected = connection?.isConnected();
|
|
779
|
-
if (!isConnected) {
|
|
780
|
-
logger.error('rabbit: isConnected - false', { connectionPurpose });
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
logger.info('rabbit: isConnected - true');
|
|
784
|
-
return true;
|
|
785
|
-
}),
|
|
786
|
-
);
|
|
787
|
-
return isEachConnectionConnected.every((isConnected) => isConnected === true);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
async gracefulShutdown(signal: string): Promise<void> {
|
|
701
|
+
async gracefulShutdown(signal: string) : Promise<void> {
|
|
791
702
|
const tagsNumber = this.consumersTags.length;
|
|
792
703
|
logger.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
|
|
793
704
|
const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
|
|
@@ -804,7 +715,3 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
804
715
|
}
|
|
805
716
|
|
|
806
717
|
export default RabbitMq;
|
|
807
|
-
|
|
808
|
-
export {
|
|
809
|
-
sendCeleryTaskViaHttp,
|
|
810
|
-
} 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
|
-
}
|