@autofleet/rabbit 3.2.21-beta.0 → 3.2.21-beta.0.1
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 +3 -1
- package/dist/index.js +51 -6
- package/dist/lib/types.d.ts +3 -1
- package/dist/lib/utils.d.ts +2 -2
- package/package.json +1 -3
- package/src/index.ts +74 -8
- package/src/lib/types.ts +4 -1
- package/src/lib/utils.ts +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EventEmitter } from 'events';
|
|
|
3
3
|
import { AmqpConnectionManager, ChannelWrapper, CreateChannelOpts } from 'amqp-connection-manager';
|
|
4
4
|
import { ConfirmChannel, ConsumeMessage, Options, Replies } from 'amqplib';
|
|
5
5
|
import { RedisConfig } from './lib/redis';
|
|
6
|
-
import { CallbackFunction, ConsumeMessageOrNull, ConsumeOptions, CustomMessageHeaders, QueuesCache, RedisLockType, ExchangesCache, QueueSetupPromisesDictionary } from './lib/types';
|
|
6
|
+
import { CallbackFunction, ConsumeMessageOrNull, ConsumeOptions, CustomMessageHeaders, QueuesCache, RedisLockType, ExchangesCache, QueueSetupPromisesDictionary, AssertExchangePromisesDictionary } from './lib/types';
|
|
7
7
|
export interface IAfRabbitMq {
|
|
8
8
|
ack: any;
|
|
9
9
|
nack: any;
|
|
@@ -66,6 +66,7 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
66
66
|
exchanges: ExchangesCache;
|
|
67
67
|
queues: QueuesCache;
|
|
68
68
|
queueSetupPromises: QueueSetupPromisesDictionary;
|
|
69
|
+
assertExchangePromises: AssertExchangePromisesDictionary;
|
|
69
70
|
options: AfRabbitOptions | undefined;
|
|
70
71
|
redisClient: any;
|
|
71
72
|
redisLock?: RedisLockType;
|
|
@@ -93,6 +94,7 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
93
94
|
consumeFromExchange(queue: string, exchange: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
|
|
94
95
|
publish(exchange: string, content: any, customHeaders?: any): Promise<boolean>;
|
|
95
96
|
sendToQueue(queue: string, content: any, options?: any, customHeaders?: any): Promise<boolean | undefined>;
|
|
97
|
+
sendToCeleryQueue(queue: string, taskName: string, data: any, options?: any, customHeaders?: any): Promise<boolean | undefined>;
|
|
96
98
|
isConnected(): Promise<boolean>;
|
|
97
99
|
gracefulShutdown(signal: string): Promise<void>;
|
|
98
100
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const events_1 = require("events");
|
|
8
8
|
const util_1 = require("util");
|
|
9
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
10
9
|
const moment_1 = __importDefault(require("moment"));
|
|
11
10
|
const redis_lock_1 = __importDefault(require("redis-lock"));
|
|
12
11
|
const amqp_connection_manager_1 = require("amqp-connection-manager");
|
|
@@ -124,6 +123,7 @@ class RabbitMq {
|
|
|
124
123
|
this.exchanges = {};
|
|
125
124
|
this.queues = {};
|
|
126
125
|
this.queueSetupPromises = {};
|
|
126
|
+
this.assertExchangePromises = {};
|
|
127
127
|
this.consumers = [];
|
|
128
128
|
this.options = options;
|
|
129
129
|
this.redisClient = redisConfig && (0, redis_1.default)(redisConfig);
|
|
@@ -199,6 +199,7 @@ class RabbitMq {
|
|
|
199
199
|
}
|
|
200
200
|
});
|
|
201
201
|
this.connection.on('disconnect', ({ err }) => {
|
|
202
|
+
// this.channel = null;
|
|
202
203
|
this.consumersTags = [];
|
|
203
204
|
debug('rabbit: connection closed');
|
|
204
205
|
if (this.options?.disableReconnect) {
|
|
@@ -266,11 +267,15 @@ class RabbitMq {
|
|
|
266
267
|
async assertExchange(exchangeName, options) {
|
|
267
268
|
const channel = await this.assertChannel();
|
|
268
269
|
if (this.exchanges[exchangeName]) {
|
|
270
|
+
delete this.assertExchangePromises[exchangeName];
|
|
269
271
|
return this.exchanges[exchangeName];
|
|
270
272
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
273
|
+
if (this.assertExchangePromises[exchangeName]) {
|
|
274
|
+
return this.assertExchangePromises[exchangeName];
|
|
275
|
+
}
|
|
276
|
+
this.assertExchangePromises[exchangeName] = (0, utils_1.assertExchangeFanout)(channel, exchangeName);
|
|
277
|
+
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
278
|
+
return this.exchanges[exchangeName];
|
|
274
279
|
}
|
|
275
280
|
async getQueueLength(queue) {
|
|
276
281
|
RabbitMq.validateName('queue', queue);
|
|
@@ -377,7 +382,6 @@ class RabbitMq {
|
|
|
377
382
|
return channel.addSetup(async (confirmChannel) => {
|
|
378
383
|
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
379
384
|
await confirmChannel.prefetch(limit, true);
|
|
380
|
-
const channelConsumerOptions = optionsWithDefaults.channelConsumeOptions ? lodash_1.default.merge(types_1.CONSUMER_DEFAULT_OPTIONS, optionsWithDefaults.channelConsumeOptions) : types_1.CONSUMER_DEFAULT_OPTIONS;
|
|
381
385
|
const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
|
|
382
386
|
if (!msg) {
|
|
383
387
|
return null;
|
|
@@ -438,7 +442,7 @@ class RabbitMq {
|
|
|
438
442
|
catch (e) {
|
|
439
443
|
await localNack(msg);
|
|
440
444
|
}
|
|
441
|
-
},
|
|
445
|
+
}, types_1.CONSUMER_DEFAULT_OPTIONS);
|
|
442
446
|
if (!consumerTag) {
|
|
443
447
|
logger_1.default.error(`rabbit: failed to consume from queue ${queue}`);
|
|
444
448
|
}
|
|
@@ -501,6 +505,47 @@ class RabbitMq {
|
|
|
501
505
|
throw e;
|
|
502
506
|
}
|
|
503
507
|
}
|
|
508
|
+
async sendToCeleryQueue(queue, taskName, data, options, customHeaders) {
|
|
509
|
+
try {
|
|
510
|
+
await this.assertChannel();
|
|
511
|
+
}
|
|
512
|
+
catch (e) {
|
|
513
|
+
logger_1.default.error(`rabbit sendToCeleryQueue: failed to assert channel when sending to queue ${queue}`, { e });
|
|
514
|
+
throw e;
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
RabbitMq.validateName('queue', queue);
|
|
518
|
+
await this.assertQueue(queue, options);
|
|
519
|
+
}
|
|
520
|
+
catch (e) {
|
|
521
|
+
logger_1.default.error(`rabbit sendToCeleryQueue: failed to assert queue ${queue}`, { e });
|
|
522
|
+
throw e;
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
// Create Celery-compatible message format
|
|
526
|
+
const celeryMessage = {
|
|
527
|
+
task: taskName,
|
|
528
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
529
|
+
args: [data],
|
|
530
|
+
};
|
|
531
|
+
const celeryHeaders = {
|
|
532
|
+
...RabbitMq.getPublishOptions(customHeaders),
|
|
533
|
+
properties: {
|
|
534
|
+
delivery_mode: 2,
|
|
535
|
+
content_type: 'application/json',
|
|
536
|
+
content_encoding: 'utf-8',
|
|
537
|
+
},
|
|
538
|
+
};
|
|
539
|
+
const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(celeryMessage)), celeryHeaders);
|
|
540
|
+
debug(`rabbit: sending to celery queue ${queue}`, { res });
|
|
541
|
+
return res;
|
|
542
|
+
}
|
|
543
|
+
catch (e) {
|
|
544
|
+
const isConnected = await this.isConnected();
|
|
545
|
+
logger_1.default.error(`rabbit sendToCeleryQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
546
|
+
throw e;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
504
549
|
async isConnected() {
|
|
505
550
|
const connection = await this.getConnection();
|
|
506
551
|
const isConnected = connection.isConnected();
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface QueuesCache {
|
|
|
8
8
|
export interface QueueSetupPromisesDictionary {
|
|
9
9
|
[key: string]: Promise<Replies.AssertQueue> | undefined;
|
|
10
10
|
}
|
|
11
|
+
export interface AssertExchangePromisesDictionary {
|
|
12
|
+
[key: string]: Promise<Replies.AssertExchange> | undefined;
|
|
13
|
+
}
|
|
11
14
|
export type CustomMessageHeaders = {
|
|
12
15
|
redisTimestampValidationKey?: string;
|
|
13
16
|
};
|
|
@@ -22,7 +25,6 @@ export interface ConsumeOptions {
|
|
|
22
25
|
useConsumeWithLock?: boolean;
|
|
23
26
|
auditContext?: any;
|
|
24
27
|
enableRabbitTrace?: boolean;
|
|
25
|
-
channelConsumeOptions?: Options.Consume;
|
|
26
28
|
}
|
|
27
29
|
export type CallbackFunction = (msg: ConsumeMessage, ack: any, nack: any) => Promise<any>;
|
|
28
30
|
export type newChannelOpts = {
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChannelWrapper } from 'amqp-connection-manager';
|
|
2
|
-
import { ConfirmChannel } from 'amqplib';
|
|
3
|
-
export declare const assertExchangeFanout: (c: ChannelWrapper | ConfirmChannel, exchangeName: string) => Promise<
|
|
2
|
+
import { ConfirmChannel, Replies } from 'amqplib';
|
|
3
|
+
export declare const assertExchangeFanout: (c: ChannelWrapper | ConfirmChannel, exchangeName: string) => Promise<Replies.AssertExchange>;
|
|
4
4
|
export declare const wrapSetImmediate: (callback: () => any) => Promise<any>;
|
|
5
5
|
export declare const rand: () => number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/rabbit",
|
|
3
|
-
"version": "3.2.21-beta.0",
|
|
3
|
+
"version": "3.2.21-beta.0.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"amqp-connection-manager": "4.1.9",
|
|
20
20
|
"amqplib": "0.10.3",
|
|
21
21
|
"bluebird": "^3.7.2",
|
|
22
|
-
"lodash": "^4.17.21",
|
|
23
22
|
"moment": "^2.29.1",
|
|
24
23
|
"redis": "^3.1.2",
|
|
25
24
|
"redis-lock": "^0.1.4"
|
|
@@ -31,7 +30,6 @@
|
|
|
31
30
|
"@autofleet/logger": "4.0.6",
|
|
32
31
|
"@types/amqplib": "0.8.2",
|
|
33
32
|
"@types/jest": "^29.5.12",
|
|
34
|
-
"@types/lodash": "^4.17.12",
|
|
35
33
|
"@types/node": "^20.14.11",
|
|
36
34
|
"@typescript-eslint/eslint-plugin": "^4.8.1",
|
|
37
35
|
"eslint": "^7.13.0",
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { EventEmitter, once } from 'events';
|
|
4
4
|
import { promisify } from 'util';
|
|
5
|
-
import _ from 'lodash';
|
|
6
5
|
import moment from 'moment';
|
|
7
6
|
import RedisLock from 'redis-lock';
|
|
8
7
|
import {
|
|
@@ -36,7 +35,10 @@ import {
|
|
|
36
35
|
CustomMessageHeaders,
|
|
37
36
|
QueuesCache,
|
|
38
37
|
RedisLockType,
|
|
39
|
-
ExchangesCache,
|
|
38
|
+
ExchangesCache,
|
|
39
|
+
CONSUMER_DEFAULT_OPTIONS,
|
|
40
|
+
QueueSetupPromisesDictionary,
|
|
41
|
+
AssertExchangePromisesDictionary,
|
|
40
42
|
} from './lib/types';
|
|
41
43
|
|
|
42
44
|
// const debug = nodeDebug('af-rabbitmq')
|
|
@@ -158,6 +160,8 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
158
160
|
|
|
159
161
|
queueSetupPromises: QueueSetupPromisesDictionary;
|
|
160
162
|
|
|
163
|
+
assertExchangePromises: AssertExchangePromisesDictionary;
|
|
164
|
+
|
|
161
165
|
options: AfRabbitOptions | undefined;
|
|
162
166
|
|
|
163
167
|
redisClient: any;
|
|
@@ -178,6 +182,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
178
182
|
this.exchanges = {};
|
|
179
183
|
this.queues = {};
|
|
180
184
|
this.queueSetupPromises = {};
|
|
185
|
+
this.assertExchangePromises = {};
|
|
181
186
|
this.consumers = [];
|
|
182
187
|
this.options = options;
|
|
183
188
|
this.redisClient = redisConfig && getRedisInstance(redisConfig);
|
|
@@ -336,6 +341,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
336
341
|
});
|
|
337
342
|
|
|
338
343
|
this.connection.on('disconnect', ({ err }) => {
|
|
344
|
+
// this.channel = null;
|
|
339
345
|
this.consumersTags = [];
|
|
340
346
|
debug('rabbit: connection closed');
|
|
341
347
|
if (this.options?.disableReconnect) {
|
|
@@ -345,6 +351,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
345
351
|
logger.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
346
352
|
}
|
|
347
353
|
});
|
|
354
|
+
|
|
348
355
|
this.connection.once('connect', async () => {
|
|
349
356
|
debug('rabbit: connection established');
|
|
350
357
|
this.creatingConnection = false;
|
|
@@ -402,12 +409,19 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
402
409
|
|
|
403
410
|
async assertExchange(exchangeName: string, options?: any) {
|
|
404
411
|
const channel: ChannelWrapper = await this.assertChannel();
|
|
412
|
+
|
|
405
413
|
if (this.exchanges[exchangeName]) {
|
|
414
|
+
delete this.assertExchangePromises[exchangeName];
|
|
406
415
|
return this.exchanges[exchangeName];
|
|
407
416
|
}
|
|
408
|
-
|
|
409
|
-
this.
|
|
410
|
-
|
|
417
|
+
|
|
418
|
+
if (this.assertExchangePromises[exchangeName]) {
|
|
419
|
+
return this.assertExchangePromises[exchangeName];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
this.assertExchangePromises[exchangeName] = assertExchangeFanout(channel, exchangeName);
|
|
423
|
+
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
424
|
+
return this.exchanges[exchangeName];
|
|
411
425
|
}
|
|
412
426
|
|
|
413
427
|
async getQueueLength(queue: string) {
|
|
@@ -532,7 +546,6 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
532
546
|
return channel.addSetup(async (confirmChannel: ConfirmChannel) => {
|
|
533
547
|
await confirmChannel.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
534
548
|
await confirmChannel.prefetch(limit, true);
|
|
535
|
-
const channelConsumerOptions = optionsWithDefaults.channelConsumeOptions ? _.merge(CONSUMER_DEFAULT_OPTIONS, optionsWithDefaults.channelConsumeOptions) : CONSUMER_DEFAULT_OPTIONS;
|
|
536
549
|
const { consumerTag } = await confirmChannel.consume(
|
|
537
550
|
queue,
|
|
538
551
|
async (msg: ConsumeMessageOrNull) => {
|
|
@@ -604,8 +617,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
604
617
|
} catch (e) {
|
|
605
618
|
await localNack(msg);
|
|
606
619
|
}
|
|
607
|
-
},
|
|
608
|
-
channelConsumerOptions,
|
|
620
|
+
}, CONSUMER_DEFAULT_OPTIONS,
|
|
609
621
|
);
|
|
610
622
|
if (!consumerTag) {
|
|
611
623
|
logger.error(`rabbit: failed to consume from queue ${queue}`);
|
|
@@ -685,6 +697,60 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
685
697
|
}
|
|
686
698
|
}
|
|
687
699
|
|
|
700
|
+
async sendToCeleryQueue(
|
|
701
|
+
queue: string,
|
|
702
|
+
taskName: string,
|
|
703
|
+
data: any,
|
|
704
|
+
options?: any,
|
|
705
|
+
customHeaders?: any,
|
|
706
|
+
): Promise<boolean | undefined> {
|
|
707
|
+
try {
|
|
708
|
+
await this.assertChannel();
|
|
709
|
+
} catch (e) {
|
|
710
|
+
logger.error(`rabbit sendToCeleryQueue: failed to assert channel when sending to queue ${queue}`, { e });
|
|
711
|
+
throw e;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
try {
|
|
715
|
+
RabbitMq.validateName('queue', queue);
|
|
716
|
+
await this.assertQueue(queue, options);
|
|
717
|
+
} catch (e) {
|
|
718
|
+
logger.error(`rabbit sendToCeleryQueue: failed to assert queue ${queue}`, { e });
|
|
719
|
+
throw e;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
try {
|
|
723
|
+
// Create Celery-compatible message format
|
|
724
|
+
const celeryMessage = {
|
|
725
|
+
task: taskName,
|
|
726
|
+
id: randomUUID(),
|
|
727
|
+
args: [data],
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
const celeryHeaders = {
|
|
731
|
+
...RabbitMq.getPublishOptions(customHeaders),
|
|
732
|
+
properties: {
|
|
733
|
+
delivery_mode: 2,
|
|
734
|
+
content_type: 'application/json',
|
|
735
|
+
content_encoding: 'utf-8',
|
|
736
|
+
},
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
const res = await this.channel?.sendToQueue(
|
|
740
|
+
queue,
|
|
741
|
+
Buffer.from(JSON.stringify(celeryMessage)),
|
|
742
|
+
celeryHeaders,
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
debug(`rabbit: sending to celery queue ${queue}`, { res });
|
|
746
|
+
return res;
|
|
747
|
+
} catch (e) {
|
|
748
|
+
const isConnected = await this.isConnected();
|
|
749
|
+
logger.error(`rabbit sendToCeleryQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
750
|
+
throw e;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
688
754
|
async isConnected() : Promise<boolean> {
|
|
689
755
|
const connection = await this.getConnection();
|
|
690
756
|
const isConnected = connection.isConnected();
|
package/src/lib/types.ts
CHANGED
|
@@ -12,6 +12,10 @@ export interface QueueSetupPromisesDictionary {
|
|
|
12
12
|
[key: string]: Promise<Replies.AssertQueue> | undefined
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface AssertExchangePromisesDictionary {
|
|
16
|
+
[key: string]: Promise<Replies.AssertExchange> | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
export type CustomMessageHeaders = {
|
|
16
20
|
redisTimestampValidationKey?: string;
|
|
17
21
|
}
|
|
@@ -27,7 +31,6 @@ export interface ConsumeOptions {
|
|
|
27
31
|
useConsumeWithLock?: boolean;
|
|
28
32
|
auditContext?: any;
|
|
29
33
|
enableRabbitTrace?: boolean;
|
|
30
|
-
channelConsumeOptions?: Options.Consume;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export type CallbackFunction = (msg: ConsumeMessage, ack: any, nack: any) => Promise<any>
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ChannelWrapper } from 'amqp-connection-manager';
|
|
2
|
-
import { ConfirmChannel } from 'amqplib';
|
|
2
|
+
import { ConfirmChannel, Replies } from 'amqplib';
|
|
3
|
+
|
|
4
|
+
export const assertExchangeFanout = async (
|
|
5
|
+
c: ChannelWrapper | ConfirmChannel,
|
|
6
|
+
exchangeName: string,
|
|
7
|
+
): Promise<Replies.AssertExchange> => c.assertExchange(exchangeName, 'fanout');
|
|
3
8
|
|
|
4
|
-
export const assertExchangeFanout = async (c: ChannelWrapper | ConfirmChannel, exchangeName: string) => c.assertExchange(exchangeName, 'fanout');
|
|
5
9
|
export const wrapSetImmediate = (callback: () => any) => new Promise<any>((resolve, reject) => {
|
|
6
10
|
setImmediate(async () => {
|
|
7
11
|
try {
|