@autofleet/rabbit 2.1.8-beta1 → 2.1.8-beta10
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 +82 -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/dump.rdb +0 -0
- package/package.json +1 -1
- package/src/index.ts +12 -4
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,21 @@ 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
|
+
try {
|
|
233
|
+
yield callback(parsedMessage, this.ack(channel, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
yield this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl });
|
|
237
|
+
}
|
|
238
|
+
})),
|
|
201
239
|
]);
|
|
202
240
|
}));
|
|
203
241
|
});
|
|
@@ -216,31 +254,49 @@ class RabbitMq {
|
|
|
216
254
|
yield c.prefetch(limit, true);
|
|
217
255
|
return Promise.all([
|
|
218
256
|
c.bindQueue(queue, exchange, ''),
|
|
219
|
-
c.consume(queue, (msg) => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
257
|
+
c.consume(queue, (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
258
|
+
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
259
|
+
// newTrace(traceTypes.RABBIT);
|
|
260
|
+
const shouldConsume = yield this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
261
|
+
logger_1.default.info('rabbit: trying to consume', { queue, shouldConsume, msg });
|
|
262
|
+
if (!shouldConsume) {
|
|
263
|
+
return this.ack(channel)(msg);
|
|
264
|
+
}
|
|
265
|
+
callback(parsedMessage, this.ack(channel, true), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }));
|
|
266
|
+
})),
|
|
223
267
|
]);
|
|
224
268
|
}));
|
|
225
269
|
});
|
|
226
270
|
}
|
|
227
|
-
publish(exchange, content) {
|
|
271
|
+
publish(exchange, content, customHeaders) {
|
|
228
272
|
return __awaiter(this, void 0, void 0, function* () {
|
|
229
273
|
RabbitMq.validateName('exchange', exchange);
|
|
230
274
|
const channel = yield this.assertChannel();
|
|
231
275
|
yield this.assertExchange(exchange);
|
|
232
|
-
return new bluebird.Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
233
|
-
|
|
234
|
-
|
|
276
|
+
return new bluebird.Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
277
|
+
try {
|
|
278
|
+
yield channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
279
|
+
return resolve();
|
|
280
|
+
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
reject(e);
|
|
283
|
+
}
|
|
235
284
|
})).timeout(this.PUBLISH_TIMEOUT, `${this.PUBLISH_ERROR_MSG}${exchange}`);
|
|
236
285
|
});
|
|
237
286
|
}
|
|
238
|
-
sendToQueue(queue, content, options) {
|
|
287
|
+
sendToQueue(queue, content, options, customHeaders) {
|
|
239
288
|
return __awaiter(this, void 0, void 0, function* () {
|
|
240
289
|
RabbitMq.validateName('queue', queue);
|
|
241
290
|
const channel = yield this.assertChannel();
|
|
242
291
|
yield this.assertQueue(queue, options);
|
|
243
|
-
|
|
292
|
+
logger_1.default.info('rabbit: sending to queue', { queue, content, customHeaders });
|
|
293
|
+
return channel.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
isConnected() {
|
|
297
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
298
|
+
const connection = yield this.getConnection();
|
|
299
|
+
return connection.isConnected();
|
|
244
300
|
});
|
|
245
301
|
}
|
|
246
302
|
}
|
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/dump.rdb
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ import moment from 'moment';
|
|
|
5
5
|
import { ConfirmChannel, Options } from 'amqplib';
|
|
6
6
|
import { AmqpConnectionManager, ChannelWrapper, connect } from 'amqp-connection-manager';
|
|
7
7
|
import { EventEmitter } from 'events';
|
|
8
|
-
import { newTrace, traceTypes } from '@autofleet/outbreak';
|
|
8
|
+
// import { newTrace, traceTypes } from '@autofleet/outbreak';
|
|
9
9
|
import logger from './logger';
|
|
10
10
|
import RabbitError from './rabbitError';
|
|
11
11
|
import getRedisInstance, { RedisConfig } from './redis';
|
|
@@ -253,13 +253,21 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
253
253
|
queue,
|
|
254
254
|
async (msg: any) => {
|
|
255
255
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
256
|
-
newTrace(traceTypes.RABBIT);
|
|
256
|
+
// newTrace(traceTypes.RABBIT);
|
|
257
257
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
258
258
|
logger.info('rabbit: trying to consume', { queue, shouldConsume, msg });
|
|
259
259
|
if (!shouldConsume) {
|
|
260
260
|
return this.ack(channel)(msg);
|
|
261
261
|
}
|
|
262
|
-
|
|
262
|
+
try {
|
|
263
|
+
await callback(
|
|
264
|
+
parsedMessage,
|
|
265
|
+
this.ack(channel, true),
|
|
266
|
+
this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }),
|
|
267
|
+
);
|
|
268
|
+
} catch (e) {
|
|
269
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl });
|
|
270
|
+
}
|
|
263
271
|
},
|
|
264
272
|
),
|
|
265
273
|
]);
|
|
@@ -284,7 +292,7 @@ class RabbitMq implements IAfRabbitMq {
|
|
|
284
292
|
queue,
|
|
285
293
|
async (msg: any) => {
|
|
286
294
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
287
|
-
newTrace(traceTypes.RABBIT);
|
|
295
|
+
// newTrace(traceTypes.RABBIT);
|
|
288
296
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
289
297
|
logger.info('rabbit: trying to consume', { queue, shouldConsume, msg });
|
|
290
298
|
if (!shouldConsume) {
|