@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 +5 -3
- package/dist/index.js +32 -27
- package/package.json +1 -1
- package/src/index.ts +44 -34
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:
|
|
73
|
-
nack: (channel:
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 (
|
|
364
|
-
await
|
|
365
|
-
await
|
|
366
|
-
const { consumerTag } = await
|
|
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(
|
|
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(
|
|
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,
|
|
409
|
+
await callback(parsedMessage, localAck, localNack);
|
|
405
410
|
}
|
|
406
411
|
catch (e) {
|
|
407
|
-
await
|
|
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([
|
|
420
|
+
this.consumersTags.push([confirmChannel, consumerTag]);
|
|
416
421
|
}
|
|
417
422
|
});
|
|
418
423
|
}
|
package/package.json
CHANGED
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:
|
|
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:
|
|
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
|
-
}:
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
513
|
-
await
|
|
514
|
-
await
|
|
515
|
-
const { consumerTag } = await
|
|
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(
|
|
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(
|
|
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
|
-
|
|
560
|
-
|
|
569
|
+
localAck,
|
|
570
|
+
localNack,
|
|
561
571
|
);
|
|
562
572
|
} catch (e) {
|
|
563
|
-
await
|
|
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([
|
|
581
|
+
this.consumersTags.push([confirmChannel, consumerTag]);
|
|
572
582
|
}
|
|
573
583
|
});
|
|
574
584
|
}
|