@autofleet/rabbit 2.1.8-beta3 → 2.1.8-beta5
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 +31 -8
- package/dist/index.js +77 -26
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +5 -0
- package/dist/mock.d.ts +11 -10
- package/dist/mock.js +1 -0
- package/dist/redis.d.ts +7 -0
- package/dist/redis.js +11 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,15 +2,35 @@
|
|
|
2
2
|
import { Options } from 'amqplib';
|
|
3
3
|
import { AmqpConnectionManager, ChannelWrapper } from 'amqp-connection-manager';
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
|
+
import { RedisConfig } from './redis';
|
|
6
|
+
export interface IAfRabbitMq {
|
|
7
|
+
ack: any;
|
|
8
|
+
nack: any;
|
|
9
|
+
assertChannel: any;
|
|
10
|
+
assertExchange: any;
|
|
11
|
+
assertQueue: any;
|
|
12
|
+
consume: any;
|
|
13
|
+
consumeFromExchange: any;
|
|
14
|
+
publish: any;
|
|
15
|
+
sendToQueue: any;
|
|
16
|
+
redisClient?: any;
|
|
17
|
+
}
|
|
5
18
|
interface ExchangesCache {
|
|
6
19
|
[key: string]: any;
|
|
7
20
|
}
|
|
21
|
+
declare type CustomMessageHeaders = {
|
|
22
|
+
redisTimestampValidationKey?: string;
|
|
23
|
+
};
|
|
8
24
|
export interface AfRabbitOptions {
|
|
9
25
|
reconnect: boolean;
|
|
10
26
|
}
|
|
11
|
-
declare class RabbitMq {
|
|
27
|
+
declare class RabbitMq implements IAfRabbitMq {
|
|
12
28
|
static parseMsg(msg: any): any;
|
|
13
29
|
static validateName(type: string, name: string): void;
|
|
30
|
+
static getPublishOptions(customHeaders?: CustomMessageHeaders): {
|
|
31
|
+
timestamp: number;
|
|
32
|
+
headers: CustomMessageHeaders;
|
|
33
|
+
};
|
|
14
34
|
PUBLISH_TIMEOUT: number;
|
|
15
35
|
PUBLISH_ERROR_MSG: string;
|
|
16
36
|
DISCONNECT_MSG: string;
|
|
@@ -21,19 +41,22 @@ declare class RabbitMq {
|
|
|
21
41
|
creatingConnection: boolean;
|
|
22
42
|
exchanges: ExchangesCache;
|
|
23
43
|
options: AfRabbitOptions | undefined;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
redisClient: any;
|
|
45
|
+
constructor(options?: AfRabbitOptions, redisConfig?: RedisConfig);
|
|
46
|
+
private shouldConsumeMessageByTimestamp;
|
|
47
|
+
ack: (channel: ChannelWrapper, shouldUpdateRedisTimestamp?: boolean) => (msg: any) => Promise<void>;
|
|
48
|
+
nack: (channel: ChannelWrapper, queue: string, options: any, deadQueueOptions: Options.AssertQueue) => (msg: any, { skipRetry, }?: any) => Promise<void>;
|
|
27
49
|
getConnection(): Promise<AmqpConnectionManager>;
|
|
28
50
|
getNewChannel(): Promise<ChannelWrapper>;
|
|
29
51
|
assertChannel(): Promise<ChannelWrapper>;
|
|
30
52
|
assertExchange(exchangeName: string, options?: any): Promise<any>;
|
|
31
|
-
getQueueLength(queue: string): Promise<
|
|
32
|
-
bindQueue(queue: string, exchange: string): Promise<
|
|
53
|
+
getQueueLength(queue: string): Promise<import("amqplib").Replies.AssertQueue>;
|
|
54
|
+
bindQueue(queue: string, exchange: string): Promise<void>;
|
|
33
55
|
assertQueue(queue: string, options?: Options.AssertQueue): Promise<void>;
|
|
34
56
|
consume(queue: string, callback: (msg: any, ack: Function, nack: Function) => any, options?: any): Promise<void>;
|
|
35
57
|
consumeFromExchange(queue: string, exchange: string, callback: (msg: any, ack: Function, nack: Function) => any, options?: any): Promise<void>;
|
|
36
|
-
publish(exchange: string, content: any): Promise<unknown>;
|
|
37
|
-
sendToQueue(queue: string, content: any, options?: any): Promise<
|
|
58
|
+
publish(exchange: string, content: any, customHeaders?: any): Promise<unknown>;
|
|
59
|
+
sendToQueue(queue: string, content: any, options?: any, customHeaders?: any): Promise<boolean>;
|
|
60
|
+
isConnected(): Promise<boolean>;
|
|
38
61
|
}
|
|
39
62
|
export default RabbitMq;
|
package/dist/index.js
CHANGED
|
@@ -34,31 +34,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
34
34
|
/* eslint-disable @typescript-eslint/ban-ts-comment,@typescript-eslint/ban-types,@typescript-eslint/no-unused-vars,consistent-return,no-async-promise-executor,no-param-reassign,no-empty */
|
|
35
35
|
// eslint-disable-next-line max-classes-per-file
|
|
36
36
|
const bluebird = __importStar(require("bluebird"));
|
|
37
|
+
const moment_1 = __importDefault(require("moment"));
|
|
37
38
|
const amqp_connection_manager_1 = require("amqp-connection-manager");
|
|
38
39
|
const events_1 = require("events");
|
|
39
|
-
|
|
40
|
+
// import { newTrace, traceTypes } from '@autofleet/outbreak';
|
|
41
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
40
42
|
const rabbitError_1 = __importDefault(require("./rabbitError"));
|
|
43
|
+
const redis_1 = __importDefault(require("./redis"));
|
|
41
44
|
const DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 48;
|
|
42
45
|
const defaultOptions = {
|
|
43
46
|
limit: 1,
|
|
44
47
|
retries: 1,
|
|
45
48
|
deadMessageTtl: DEFAULT_DEAD_TTL_TWO_DAYS,
|
|
46
49
|
};
|
|
50
|
+
const SECONDS_TO_MILLISECONDS = 1000;
|
|
47
51
|
const assertExchangeFanout = (c, exchangeName) => c.assertExchange(exchangeName, 'fanout');
|
|
48
52
|
const connectionCreatedConst = 'connectionCreated';
|
|
49
53
|
class RabbitMq {
|
|
50
|
-
constructor(options) {
|
|
54
|
+
constructor(options, redisConfig) {
|
|
51
55
|
this.PUBLISH_TIMEOUT = Number(process.env.RABBITMQ_PUBLISH_TIMEOUT) || 60000;
|
|
52
56
|
this.PUBLISH_ERROR_MSG = `rabbit: publish timeout(${this.PUBLISH_TIMEOUT}ms) has pass, exchange: `;
|
|
53
57
|
this.DISCONNECT_MSG = 'rabbit: connection disconnect';
|
|
54
58
|
this.RESCONNECT_MSG = 'rabbit: reconnecting';
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
this.shouldConsumeMessageByTimestamp = (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
const { properties: { timestamp, headers } } = msg;
|
|
61
|
+
if (timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey) && this.redisClient) {
|
|
62
|
+
const lastMessageTimestamp = yield this.redisClient.getAsync(headers.redisTimestampValidationKey);
|
|
63
|
+
logger_1.default.info('rabbit: checking if should consume params', {
|
|
64
|
+
msg, timestamp, headers, lastMessageTimestamp,
|
|
65
|
+
});
|
|
66
|
+
return !lastMessageTimestamp || (parseInt(lastMessageTimestamp, 10) <= parseInt(timestamp, 10));
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
this.ack = (channel, shouldUpdateRedisTimestamp = false) => (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
yield channel.ack(msg);
|
|
72
|
+
const { properties: { timestamp, headers } } = msg;
|
|
73
|
+
if (shouldUpdateRedisTimestamp && timestamp && (headers === null || headers === void 0 ? void 0 : headers.redisTimestampValidationKey) && this.redisClient) {
|
|
74
|
+
const parsedTimestamp = parseInt(timestamp, 10);
|
|
75
|
+
yield this.redisClient.setAsync(headers.redisTimestampValidationKey, parsedTimestamp, 'EX', 3600);
|
|
58
76
|
}
|
|
59
77
|
});
|
|
60
|
-
this.nack = (queue, options, deadQueueOptions) => (msg, { skipRetry = false, } = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
if (
|
|
78
|
+
this.nack = (channel, queue, options, deadQueueOptions) => (msg, { skipRetry = false, } = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
if (channel) {
|
|
62
80
|
if (!skipRetry
|
|
63
81
|
&& (!msg.content['x-retry-count']
|
|
64
82
|
|| msg.content['x-retry-count'] < options.retries)) {
|
|
@@ -70,7 +88,7 @@ class RabbitMq {
|
|
|
70
88
|
yield this.assertQueue(deadQueue, deadQueueOptions);
|
|
71
89
|
yield this.sendToQueue(deadQueue, msg.content, deadQueueOptions);
|
|
72
90
|
}
|
|
73
|
-
yield
|
|
91
|
+
yield channel.ack(msg);
|
|
74
92
|
}
|
|
75
93
|
});
|
|
76
94
|
this.em = new events_1.EventEmitter();
|
|
@@ -79,6 +97,7 @@ class RabbitMq {
|
|
|
79
97
|
this.creatingConnection = false;
|
|
80
98
|
this.exchanges = {};
|
|
81
99
|
this.options = options;
|
|
100
|
+
this.redisClient = redisConfig && redis_1.default(redisConfig);
|
|
82
101
|
}
|
|
83
102
|
static parseMsg(msg) {
|
|
84
103
|
let { content } = msg;
|
|
@@ -94,19 +113,27 @@ class RabbitMq {
|
|
|
94
113
|
throw new rabbitError_1.default(`error while using ${type} with no name`);
|
|
95
114
|
}
|
|
96
115
|
}
|
|
116
|
+
static getPublishOptions(customHeaders = {}) {
|
|
117
|
+
return {
|
|
118
|
+
timestamp: moment_1.default().unix(),
|
|
119
|
+
headers: customHeaders,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
97
122
|
getConnection() {
|
|
98
123
|
return __awaiter(this, void 0, void 0, function* () {
|
|
99
124
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
100
125
|
if (this.creatingConnection) {
|
|
101
|
-
this.em.
|
|
126
|
+
this.em.once(connectionCreatedConst, resolve);
|
|
102
127
|
return;
|
|
103
128
|
}
|
|
104
129
|
if (this.connection !== null) {
|
|
105
|
-
return this.connection;
|
|
130
|
+
return resolve(this.connection);
|
|
106
131
|
}
|
|
107
132
|
this.creatingConnection = true;
|
|
133
|
+
const username = process.env.RABBITMQ_USERNAME || 'guest';
|
|
134
|
+
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
108
135
|
const host = process.env.RABBITMQ_SERVICE_HOST || '';
|
|
109
|
-
const connection = yield amqp_connection_manager_1.connect([`amqp://${host}`]);
|
|
136
|
+
const connection = yield amqp_connection_manager_1.connect([`amqp://${username}:${password}@${host}`]);
|
|
110
137
|
this.connection = connection;
|
|
111
138
|
this.connection.on('disconnect', ({ err }) => {
|
|
112
139
|
var _a;
|
|
@@ -136,8 +163,8 @@ class RabbitMq {
|
|
|
136
163
|
if (this.channel) {
|
|
137
164
|
return resolve(this.channel);
|
|
138
165
|
}
|
|
139
|
-
const connection = yield this.getConnection();
|
|
140
166
|
try {
|
|
167
|
+
const connection = yield this.getConnection();
|
|
141
168
|
if (this.channel === null) {
|
|
142
169
|
this.channel = connection.createChannel({});
|
|
143
170
|
}
|
|
@@ -194,10 +221,16 @@ class RabbitMq {
|
|
|
194
221
|
yield c.assertQueue(queue);
|
|
195
222
|
yield c.prefetch(limit, true);
|
|
196
223
|
return Promise.all([
|
|
197
|
-
c.consume(queue, (msg) => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
224
|
+
c.consume(queue, (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
225
|
+
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
226
|
+
// newTrace(traceTypes.RABBIT);
|
|
227
|
+
const shouldConsume = yield this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
228
|
+
logger_1.default.info('rabbit: trying to consume', { queue, shouldConsume, msg });
|
|
229
|
+
if (!shouldConsume) {
|
|
230
|
+
return this.ack(channel)(msg);
|
|
231
|
+
}
|
|
232
|
+
callback(parsedMessage, this.ack(channel, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
|
|
233
|
+
})),
|
|
201
234
|
]);
|
|
202
235
|
}));
|
|
203
236
|
});
|
|
@@ -216,31 +249,49 @@ class RabbitMq {
|
|
|
216
249
|
yield c.prefetch(limit, true);
|
|
217
250
|
return Promise.all([
|
|
218
251
|
c.bindQueue(queue, exchange, ''),
|
|
219
|
-
c.consume(queue, (msg) => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
252
|
+
c.consume(queue, (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
253
|
+
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
254
|
+
// newTrace(traceTypes.RABBIT);
|
|
255
|
+
const shouldConsume = yield this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
256
|
+
logger_1.default.info('rabbit: trying to consume', { queue, shouldConsume, msg });
|
|
257
|
+
if (!shouldConsume) {
|
|
258
|
+
return this.ack(channel)(msg);
|
|
259
|
+
}
|
|
260
|
+
callback(parsedMessage, this.ack(channel, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
|
|
261
|
+
})),
|
|
223
262
|
]);
|
|
224
263
|
}));
|
|
225
264
|
});
|
|
226
265
|
}
|
|
227
|
-
publish(exchange, content) {
|
|
266
|
+
publish(exchange, content, customHeaders) {
|
|
228
267
|
return __awaiter(this, void 0, void 0, function* () {
|
|
229
268
|
RabbitMq.validateName('exchange', exchange);
|
|
230
269
|
const channel = yield this.assertChannel();
|
|
231
270
|
yield this.assertExchange(exchange);
|
|
232
|
-
return new bluebird.Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
233
|
-
|
|
234
|
-
|
|
271
|
+
return new bluebird.Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
272
|
+
try {
|
|
273
|
+
yield channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
274
|
+
return resolve();
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
reject(e);
|
|
278
|
+
}
|
|
235
279
|
})).timeout(this.PUBLISH_TIMEOUT, `${this.PUBLISH_ERROR_MSG}${exchange}`);
|
|
236
280
|
});
|
|
237
281
|
}
|
|
238
|
-
sendToQueue(queue, content, options) {
|
|
282
|
+
sendToQueue(queue, content, options, customHeaders) {
|
|
239
283
|
return __awaiter(this, void 0, void 0, function* () {
|
|
240
284
|
RabbitMq.validateName('queue', queue);
|
|
241
285
|
const channel = yield this.assertChannel();
|
|
242
286
|
yield this.assertQueue(queue, options);
|
|
243
|
-
|
|
287
|
+
logger_1.default.info('rabbit: sending to queue', { queue, content, customHeaders });
|
|
288
|
+
return channel.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
isConnected() {
|
|
292
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
293
|
+
const connection = yield this.getConnection();
|
|
294
|
+
return connection.isConnected();
|
|
244
295
|
});
|
|
245
296
|
}
|
|
246
297
|
}
|
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
package/dist/mock.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import 'jest';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { IAfRabbitMq } from './index';
|
|
3
|
+
declare class RabbitMq implements IAfRabbitMq {
|
|
4
|
+
ack: any;
|
|
5
|
+
nack: any;
|
|
6
|
+
assertChannel: any;
|
|
7
|
+
assertExchange: any;
|
|
8
|
+
assertQueue: any;
|
|
9
|
+
consume: any;
|
|
10
|
+
consumeFromExchange: any;
|
|
11
|
+
publish: any;
|
|
12
|
+
sendToQueue: any;
|
|
12
13
|
}
|
|
13
14
|
export default RabbitMq;
|
package/dist/mock.js
CHANGED
package/dist/redis.d.ts
ADDED
package/dist/redis.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
7
|
+
const redis = require('redis');
|
|
8
|
+
bluebird_1.default.promisifyAll(redis.RedisClient.prototype);
|
|
9
|
+
bluebird_1.default.promisifyAll(redis.Multi.prototype);
|
|
10
|
+
const getRedisInstance = (config) => redis.createClient(config);
|
|
11
|
+
exports.default = getRedisInstance;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/rabbit",
|
|
3
|
-
"version": "2.1.8-
|
|
3
|
+
"version": "2.1.8-beta5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@types/amqp-connection-manager": "^2.0.10",
|
|
20
20
|
"@types/amqplib": "^0.5.16",
|
|
21
21
|
"@types/uuid": "^8.3.3",
|
|
22
|
-
"amqp-connection-manager": "^3.
|
|
22
|
+
"amqp-connection-manager": "^3.7.0",
|
|
23
23
|
"amqplib": "^0.6.0",
|
|
24
24
|
"bluebird": "^3.7.2",
|
|
25
25
|
"moment": "^2.29.1",
|