@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/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
- AUTOMATION_ID_HEADER,
23
- ConnectionPurpose,
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
- publishChannel: ChannelWrapper | null;
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
- connectionsMap: {
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.publishChannel = null;
182
- this.publishChannelSetupPromise = null;
183
- this.connectionsMap = {
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(connectionPurpose: ConnectionPurpose) {
295
- return new Promise<AmqpConnectionManager | undefined | null>(async (resolve, reject) => {
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(connectionCreatedEventName, resolve);
320
- this.em.once(connectionFailedEventName, reject);
296
+ this.em.once(CONNECTION_CREATED_CONST, resolve);
297
+ this.em.once(CONNECTION_FAILED_CONST, reject);
321
298
  return;
322
299
  }
323
- this.connectionsMap[connectionPurpose].creatingConnection = true;
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 newConnection: AmqpConnectionManager = await connect(defaultUrls, {
317
+ const connection: AmqpConnectionManager = await connect(defaultUrls, {
341
318
  findServers,
342
319
  });
343
320
 
344
- this.connectionsMap[connectionPurpose].connection = newConnection;
345
- logger.info(`rabbit: created new connection ${connectionPurpose}`);
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(connectionFailedEventName, err);
327
+ this.em.emit(CONNECTION_FAILED_CONST, err);
353
328
  }
354
329
  });
355
330
 
356
- newConnection.on('connectFailed', (err) => {
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(connectionFailedEventName, err);
337
+ this.em.emit(CONNECTION_FAILED_CONST, err);
363
338
  }
364
339
  });
365
340
 
366
- newConnection.on('disconnect', ({ err }) => {
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
- newConnection.once('connect', async () => {
377
- this.connectionsMap[connectionPurpose].creatingConnection = false;
378
- this.em.emit(connectionCreatedEventName, newConnection);
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(newConnection);
356
+ resolve(connection);
381
357
  });
382
358
  });
383
359
  }
384
360
 
385
- async getNewChannel({
386
- name = rand().toString(), onClose = null, options = {}, connectionPurpose = ConnectionPurpose.Consume,
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(connectionPurpose);
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
- if (!connection) {
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, connectionPurpose = ConnectionPurpose.Consume }: assertChannelOpts): Promise<ChannelWrapper> {
414
- debug('rabbit: start assert channel', { connectionPurpose, publishPromise: this.publishChannelSetupPromise, channel: this.publishChannel });
415
- if (!this.publishChannelSetupPromise || (!this.publishChannel && connectionPurpose === ConnectionPurpose.Publish)) {
416
- this.publishChannelSetupPromise = new Promise<ChannelWrapper>(async (resolve, reject) => {
417
- if (this.publishChannel && !force) {
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
- try {
422
- const channel = await this.getNewChannel({ connectionPurpose });
423
- debug('rabbit: new channel got', { connectionPurpose, channel: this.publishChannel });
424
- channel.on('error', (err) => {
425
- logger.error('rabbit: channel error', { err });
426
- });
427
- if (connectionPurpose === ConnectionPurpose.Publish) {
428
- this.publishChannel = channel;
429
- }
430
- resolve(channel);
431
- } catch (e) {
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: any = { connectionPurpose: ConnectionPurpose.Consume }) {
440
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose: options.connectionPurpose });
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
- if (this.assertExchangePromises[exchangeName]) {
447
- return this.assertExchangePromises[exchangeName];
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, connectionPurpose: ConnectionPurpose = ConnectionPurpose.Consume): Promise<Replies.AssertQueue> {
413
+ async getQueueLength(queue: string) {
456
414
  RabbitMq.validateName('queue', queue);
457
- const { connection } = this.connectionsMap[connectionPurpose];
458
- const { publishChannel } = this;
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 publishChannel?.checkQueue(queue);
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, connectionPurpose: ConnectionPurpose) {
423
+ private async deleteQueue(queue: string) {
467
424
  RabbitMq.validateName('queue', queue);
468
- const channel: ChannelWrapper = await this.assertChannel({ connectionPurpose });
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({ connectionPurpose: ConnectionPurpose.Publish });
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, connectionPurpose: ConnectionPurpose, options?: Options.AssertQueue): Promise<Replies.AssertQueue> {
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({ connectionPurpose });
441
+ const channel: ChannelWrapper = await this.assertChannel();
495
442
  debug('assertQueue->channel.addSetup', { queueName });
496
- await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, localeOptions));
443
+ await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
497
444
  debug('assertQueue->channel.assertQueue', { queueName });
498
- queue = await channel.assertQueue(queueName, localeOptions);
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, connectionPurpose });
504
- await this.deleteQueue(queueName, connectionPurpose);
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, localeOptions));
454
+ await channel.addSetup((setupChannel: ConfirmChannel) => setupChannel.assertQueue(queueName, options));
508
455
  debug('retrying assertQueue->channel.assertQueue', { queueName });
509
- queue = await channel.assertQueue(queueName, localeOptions);
456
+ queue = await channel.assertQueue(queueName, options);
510
457
  } else {
511
458
  throw e;
512
459
  }
513
460
  }
514
461
 
515
- this.queues[queueName] = queue;
462
+ this.queues[queueName] = queueName;
516
463
  return queue;
517
464
  }
518
465
 
519
- static shouldUseQuorum(queueName: string): boolean {
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, connectionPurpose, options);
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: boolean = this.consumers.some((consumer) => consumer.queue === queue);
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({ connectionPurpose: ConnectionPurpose.Consume });
531
+ const channel = await this.getNewChannel({ name: `${this.podId}_queue_${queue}` });
602
532
  return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
603
- const q = await this.assertQueue(queue, ConnectionPurpose.Consume, optionsWithDefaults);
604
- await confirmChannel.prefetch(limit, false);
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: `consume - exchange - ${exchange} -queue - ${queue}` });
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, false);
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({ connectionPurpose: ConnectionPurpose.Publish });
720
- await this.assertExchange(exchange, { connectionPurpose: ConnectionPurpose.Publish });
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
- try {
734
- await this.assertChannel({ connectionPurpose: ConnectionPurpose.Publish });
735
- } catch (e) {
736
- logger.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
737
- throw e;
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
- try {
741
- RabbitMq.validateName('queue', queue);
742
- await this.assertQueue(queue, ConnectionPurpose.Publish, options);
743
- } catch (e) {
744
- logger.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
745
- throw e;
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
- const res = await this.publishChannel?.sendToQueue(queue,
750
- Buffer.from(JSON.stringify(content)),
751
- RabbitMq.getPublishOptions(customHeaders));
752
- debug(`rabbit: sending to queue ${queue}`, { res });
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(`rabbit sendToQueue: failed to send to queue ${queue}`, { e });
756
- throw e;
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 isConnected(): Promise<boolean> {
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
- }