@autofleet/rabbit 3.2.3 → 3.2.4

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 CHANGED
@@ -17,6 +17,9 @@ export interface IAfRabbitMq {
17
17
  sendToQueue: any;
18
18
  redisClient?: any;
19
19
  }
20
+ interface NackOptions {
21
+ skipRetry?: boolean;
22
+ }
20
23
  export interface AfRabbitOptions {
21
24
  disableReconnect?: boolean;
22
25
  /**
@@ -69,8 +72,8 @@ declare class RabbitMq implements IAfRabbitMq {
69
72
  private consumers;
70
73
  constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig);
71
74
  private shouldConsumeMessageByTimestamp;
72
- ack: (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: null) => (userMsg: ConsumeMessage) => Promise<any>;
73
- nack: (channel: ChannelWrapper, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull, releaseLock: any) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: any) => Promise<any>;
75
+ ack: (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: null) => (userMsg: ConsumeMessage) => Promise<any>;
76
+ nack: (channel: ConfirmChannel, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull, releaseLock: any) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: NackOptions) => Promise<any>;
74
77
  getConnection(): Promise<AmqpConnectionManager>;
75
78
  getNewChannel({ name, onClose }?: newChannelOpts): Promise<ChannelWrapper>;
76
79
  assertChannel({ force }?: assertChannelOpts): Promise<ChannelWrapper>;
@@ -80,7 +83,6 @@ declare class RabbitMq implements IAfRabbitMq {
80
83
  bindQueue(queue: string, exchange: string): Promise<void>;
81
84
  assertQueue(queueName: string, options?: Options.AssertQueue): Promise<any>;
82
85
  private saveConsumer;
83
- private loadConsumers;
84
86
  consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
85
87
  private lockRedisIfNeeded;
86
88
  private unlockRedisIfNeeded;
package/dist/index.js CHANGED
@@ -75,7 +75,6 @@ class RabbitMq {
75
75
  }
76
76
  else {
77
77
  logger_1.default.error('no channel or msg', {
78
- channel: channel ? channel.name : '',
79
78
  msg,
80
79
  });
81
80
  }
@@ -193,8 +192,6 @@ class RabbitMq {
193
192
  });
194
193
  this.connection.on('disconnect', ({ err }) => {
195
194
  debug('rabbit: connection closed');
196
- this.exchanges = {};
197
- this.queues = {};
198
195
  if (this.options?.disableReconnect) {
199
196
  logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
200
197
  this.blockReconnect = true;
@@ -205,7 +202,6 @@ class RabbitMq {
205
202
  });
206
203
  this.connection.once('connect', async () => {
207
204
  debug('rabbit: connection established');
208
- await this.loadConsumers();
209
205
  this.creatingConnection = false;
210
206
  this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
211
207
  isResolved = true;
@@ -219,7 +215,7 @@ class RabbitMq {
219
215
  const channel = connection.createChannel({});
220
216
  let isResolved = false;
221
217
  channel.on('error', (err) => {
222
- logger_1.default.error(`rabbit: channel ${name} error`, { err });
218
+ logger_1.default.error(`rabbit: channel error ${name} error`, { err });
223
219
  if (!isResolved) {
224
220
  isResolved = true;
225
221
  reject(err);
@@ -267,9 +263,12 @@ class RabbitMq {
267
263
  }
268
264
  async getQueueLength(queue) {
269
265
  RabbitMq.validateName('queue', queue);
270
- const channel = await this.assertChannel();
266
+ const { channel } = this;
267
+ if (!channel) {
268
+ throw new Error('channel is not defined');
269
+ }
271
270
  debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
272
- return channel.checkQueue(queue);
271
+ return channel?.checkQueue(queue);
273
272
  }
274
273
  async deleteQueue(queue) {
275
274
  RabbitMq.validateName('queue', queue);
@@ -322,18 +321,8 @@ class RabbitMq {
322
321
  options,
323
322
  });
324
323
  }
325
- async loadConsumers() {
326
- debug('rabbit: loading consumers', { consumers: this.consumers.length });
327
- if (this.consumers.length > 0) {
328
- await Promise.all(this.consumers.map((consumer) => this
329
- .consumeFromRabbit(consumer.queue, consumer.callback, consumer.options)));
330
- }
331
- }
332
324
  async consume(queue, callback, options) {
333
- if (this.connection && !this.creatingConnection) {
334
- this.consumeFromRabbit(queue, callback, options);
335
- }
336
- return this.saveConsumer(queue, callback, options);
325
+ return this.consumeFromRabbit(queue, callback, options);
337
326
  }
338
327
  async lockRedisIfNeeded(msg, options) {
339
328
  const { properties: { headers } } = msg;
@@ -360,10 +349,10 @@ class RabbitMq {
360
349
  logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
361
350
  }
362
351
  const channel = await this.getNewChannel({ name: `consume-queue-${queue}` });
363
- return channel.addSetup(async (c) => {
364
- await c.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
365
- await c.prefetch(limit, true);
366
- const { consumerTag } = await c.consume(queue, async (msg) => {
352
+ return channel.addSetup(async (confirmChannel) => {
353
+ await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
354
+ await confirmChannel.prefetch(limit, true);
355
+ const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
367
356
  if (!msg) {
368
357
  return null;
369
358
  }
@@ -385,7 +374,7 @@ class RabbitMq {
385
374
  }
386
375
  catch (e) {
387
376
  logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
388
- await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
377
+ await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
389
378
  }
390
379
  }
391
380
  if (traceId) {
@@ -398,13 +387,29 @@ class RabbitMq {
398
387
  const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
399
388
  if (!shouldConsume) {
400
389
  await this.unlockRedisIfNeeded(releaseLock);
401
- return this.ack(channel, msg)(msg);
390
+ return this.ack(confirmChannel, msg)(msg);
402
391
  }
392
+ let messageAcked = false;
393
+ // setting the localAck function to be used in the callback
394
+ const localAck = async () => {
395
+ if (messageAcked) {
396
+ return;
397
+ }
398
+ messageAcked = true;
399
+ return this.ack(confirmChannel, msg, true, releaseLock)(msg);
400
+ };
401
+ const localNack = async (_, nackOptions = {}) => {
402
+ if (messageAcked) {
403
+ return;
404
+ }
405
+ messageAcked = true;
406
+ return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
407
+ };
403
408
  try {
404
- await callback(parsedMessage, this.ack(channel, msg, true, releaseLock), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock));
409
+ await callback(parsedMessage, localAck, localNack);
405
410
  }
406
411
  catch (e) {
407
- await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
412
+ await localNack(msg);
408
413
  }
409
414
  }, types_1.CONSUMER_DEFAULT_OPTIONS);
410
415
  if (!consumerTag) {
@@ -412,7 +417,7 @@ class RabbitMq {
412
417
  }
413
418
  else {
414
419
  logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
415
- this.consumersTags.push([c, consumerTag]);
420
+ this.consumersTags.push([confirmChannel, consumerTag]);
416
421
  }
417
422
  });
418
423
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/rabbit",
3
- "version": "3.2.3",
3
+ "version": "3.2.4",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/index.ts CHANGED
@@ -53,6 +53,10 @@ export interface IAfRabbitMq {
53
53
  redisClient?: any;
54
54
  }
55
55
 
56
+ interface NackOptions {
57
+ skipRetry?: boolean;
58
+ }
59
+
56
60
  export interface AfRabbitOptions {
57
61
  disableReconnect?: boolean;
58
62
 
@@ -194,7 +198,7 @@ class RabbitMq implements IAfRabbitMq {
194
198
  return false;
195
199
  }
196
200
 
197
- public ack = (channel: ChannelWrapper, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
201
+ public ack = (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg: ConsumeMessage) : Promise<any> => {
198
202
  if (msg) {
199
203
  await channel.ack(msg);
200
204
  const { properties: { headers } } = msg;
@@ -209,7 +213,7 @@ class RabbitMq implements IAfRabbitMq {
209
213
  }
210
214
 
211
215
  public nack = (
212
- channel: ChannelWrapper,
216
+ channel: ConfirmChannel,
213
217
  queue: string,
214
218
  options: any,
215
219
  deadQueueOptions: Options.AssertQueue,
@@ -219,7 +223,7 @@ class RabbitMq implements IAfRabbitMq {
219
223
  userMsg: ConsumeMessageOrNull,
220
224
  {
221
225
  skipRetry = false,
222
- }: any = { },
226
+ }: NackOptions = { },
223
227
  ) : Promise<any> => {
224
228
  await this.unlockRedisIfNeeded(releaseLock);
225
229
  if (channel && msg) {
@@ -248,7 +252,6 @@ class RabbitMq implements IAfRabbitMq {
248
252
  await channel.ack(msg);
249
253
  } else {
250
254
  logger.error('no channel or msg', {
251
- channel: channel ? channel.name : '',
252
255
  msg,
253
256
  });
254
257
  }
@@ -319,8 +322,6 @@ class RabbitMq implements IAfRabbitMq {
319
322
 
320
323
  this.connection.on('disconnect', ({ err }) => {
321
324
  debug('rabbit: connection closed');
322
- this.exchanges = {};
323
- this.queues = {};
324
325
  if (this.options?.disableReconnect) {
325
326
  logger.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
326
327
  this.blockReconnect = true;
@@ -330,7 +331,6 @@ class RabbitMq implements IAfRabbitMq {
330
331
  });
331
332
  this.connection.once('connect', async () => {
332
333
  debug('rabbit: connection established');
333
- await this.loadConsumers();
334
334
  this.creatingConnection = false;
335
335
  this.em.emit(CONNECTION_CREATED_CONST, connection);
336
336
  isResolved = true;
@@ -347,7 +347,7 @@ class RabbitMq implements IAfRabbitMq {
347
347
 
348
348
  let isResolved = false;
349
349
  channel.on('error', (err) => {
350
- logger.error(`rabbit: channel ${name} error`, { err });
350
+ logger.error(`rabbit: channel error ${name} error`, { err });
351
351
  if (!isResolved) {
352
352
  isResolved = true;
353
353
  reject(err);
@@ -399,9 +399,12 @@ class RabbitMq implements IAfRabbitMq {
399
399
 
400
400
  async getQueueLength(queue: string) {
401
401
  RabbitMq.validateName('queue', queue);
402
- const channel: ChannelWrapper = await this.assertChannel();
402
+ const { channel } = this;
403
+ if (!channel) {
404
+ throw new Error('channel is not defined');
405
+ }
403
406
  debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
404
- return channel.checkQueue(queue);
407
+ return channel?.checkQueue(queue);
405
408
  }
406
409
 
407
410
  private async deleteQueue(queue: string) {
@@ -459,21 +462,8 @@ class RabbitMq implements IAfRabbitMq {
459
462
  });
460
463
  }
461
464
 
462
- private async loadConsumers() {
463
- debug('rabbit: loading consumers', { consumers: this.consumers.length });
464
- if (this.consumers.length > 0) {
465
- await Promise.all(
466
- this.consumers.map((consumer) => this
467
- .consumeFromRabbit(consumer.queue, consumer.callback, consumer.options)),
468
- );
469
- }
470
- }
471
-
472
465
  async consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any> {
473
- if (this.connection && !this.creatingConnection) {
474
- this.consumeFromRabbit(queue, callback, options);
475
- }
476
- return this.saveConsumer(queue, callback, options);
466
+ return this.consumeFromRabbit(queue, callback, options);
477
467
  }
478
468
 
479
469
  private async lockRedisIfNeeded(msg: any, options: any) {
@@ -509,10 +499,10 @@ class RabbitMq implements IAfRabbitMq {
509
499
  logger.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
510
500
  }
511
501
  const channel: ChannelWrapper = await this.getNewChannel({ name: `consume-queue-${queue}` });
512
- return channel.addSetup(async (c: ConfirmChannel) => {
513
- await c.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
514
- await c.prefetch(limit, true);
515
- const { consumerTag } = await c.consume(
502
+ return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
503
+ await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
504
+ await confirmChannel.prefetch(limit, true);
505
+ const { consumerTag } = await confirmChannel.consume(
516
506
  queue,
517
507
  async (msg: ConsumeMessageOrNull) => {
518
508
  if (!msg) {
@@ -536,7 +526,7 @@ class RabbitMq implements IAfRabbitMq {
536
526
  ]);
537
527
  } catch (e) {
538
528
  logger.error('rabbit: failed to setRabbitTrace', { userId, e });
539
- await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
529
+ await this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
540
530
  }
541
531
  }
542
532
 
@@ -551,16 +541,36 @@ class RabbitMq implements IAfRabbitMq {
551
541
  const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
552
542
  if (!shouldConsume) {
553
543
  await this.unlockRedisIfNeeded(releaseLock);
554
- return this.ack(channel, msg)(msg);
544
+ return this.ack(confirmChannel, msg)(msg);
555
545
  }
546
+
547
+ let messageAcked = false;
548
+ // setting the localAck function to be used in the callback
549
+
550
+ const localAck = async () => {
551
+ if (messageAcked) {
552
+ return;
553
+ }
554
+ messageAcked = true;
555
+ return this.ack(confirmChannel, msg, true, releaseLock)(msg);
556
+ };
557
+
558
+ const localNack = async (_: ConsumeMessageOrNull, nackOptions: NackOptions = {}) => {
559
+ if (messageAcked) {
560
+ return;
561
+ }
562
+ messageAcked = true;
563
+ return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
564
+ };
565
+
556
566
  try {
557
567
  await callback(
558
568
  parsedMessage,
559
- this.ack(channel, msg, true, releaseLock),
560
- this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock),
569
+ localAck,
570
+ localNack,
561
571
  );
562
572
  } catch (e) {
563
- await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
573
+ await localNack(msg);
564
574
  }
565
575
  }, CONSUMER_DEFAULT_OPTIONS,
566
576
  );
@@ -568,7 +578,7 @@ class RabbitMq implements IAfRabbitMq {
568
578
  logger.error(`rabbit: failed to consume from queue ${queue}`);
569
579
  } else {
570
580
  logger.info(`rabbit: adding tag ${consumerTag} to the array.`);
571
- this.consumersTags.push([c, consumerTag]);
581
+ this.consumersTags.push([confirmChannel, consumerTag]);
572
582
  }
573
583
  });
574
584
  }