@autofleet/rabbit 3.2.2-2.beta-0 → 3.2.3
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/.nvmrc +1 -1
- package/dist/index.d.ts +18 -27
- package/dist/index.js +171 -241
- package/dist/lib/redis.d.ts +1 -1
- package/dist/lib/types.d.ts +8 -20
- package/dist/lib/types.js +1 -7
- package/dist/lib/utils.js +3 -6
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +2 -5
- package/package.json +13 -12
- package/src/index.ts +155 -241
- package/src/lib/types.ts +1 -16
- package/src/logger.ts +1 -1
- package/tsconfig.json +2 -5
package/dist/index.js
CHANGED
|
@@ -10,7 +10,6 @@ const moment_1 = __importDefault(require("moment"));
|
|
|
10
10
|
const redis_lock_1 = __importDefault(require("redis-lock"));
|
|
11
11
|
const amqp_connection_manager_1 = require("amqp-connection-manager");
|
|
12
12
|
const zehut_1 = require("@autofleet/zehut");
|
|
13
|
-
const node_crypto_1 = require("node:crypto");
|
|
14
13
|
const logger_1 = __importDefault(require("./logger"));
|
|
15
14
|
const rabbitError_1 = __importDefault(require("./lib/rabbitError"));
|
|
16
15
|
const redis_1 = __importDefault(require("./lib/redis"));
|
|
@@ -18,43 +17,10 @@ const utils_1 = require("./lib/utils");
|
|
|
18
17
|
const consts_1 = require("./lib/consts");
|
|
19
18
|
const types_1 = require("./lib/types");
|
|
20
19
|
// const debug = nodeDebug('af-rabbitmq')
|
|
21
|
-
const debug = logger_1.default.
|
|
20
|
+
const debug = logger_1.default.info;
|
|
22
21
|
const PUBLISH_TIMEOUT = 1000 * 10;
|
|
23
22
|
const HEARTBEAT = '60';
|
|
24
23
|
class RabbitMq {
|
|
25
|
-
static parseMsg(msg) {
|
|
26
|
-
let { content } = msg;
|
|
27
|
-
content = content.toString();
|
|
28
|
-
try {
|
|
29
|
-
content = JSON.parse(content);
|
|
30
|
-
}
|
|
31
|
-
catch (e) { }
|
|
32
|
-
return {
|
|
33
|
-
...msg,
|
|
34
|
-
content,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
static validateName(type, name) {
|
|
38
|
-
if (!name || name === '') {
|
|
39
|
-
throw new rabbitError_1.default(`error while using ${type} with no name`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
static getPublishOptions(customHeaders = {}) {
|
|
43
|
-
const trace = (0, zehut_1.getCurrentPayload)();
|
|
44
|
-
const user = trace?.context?.get(consts_1.USER_OBJECT);
|
|
45
|
-
const traceId = trace?.context?.get(consts_1.TRACING_HEADER);
|
|
46
|
-
const outbreakTrace = zehut_1.outbreak.getCurrentContext();
|
|
47
|
-
return {
|
|
48
|
-
timestamp: (0, moment_1.default)().unix(),
|
|
49
|
-
timeout: PUBLISH_TIMEOUT,
|
|
50
|
-
headers: {
|
|
51
|
-
creationTimestamp: (0, moment_1.default)().valueOf(),
|
|
52
|
-
...customHeaders,
|
|
53
|
-
[consts_1.USER_TRACING_HEADER]: user?.id,
|
|
54
|
-
[consts_1.TRACING_HEADER]: traceId || outbreakTrace?.context?.get(consts_1.TRACING_HEADER),
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
24
|
constructor(options, redisConfig) {
|
|
59
25
|
this.DISCONNECT_MSG = 'rabbit: connection disconnect';
|
|
60
26
|
this.RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
|
|
@@ -73,7 +39,6 @@ class RabbitMq {
|
|
|
73
39
|
};
|
|
74
40
|
this.ack = (channel, msg, shouldUpdateRedisTimestamp = false, releaseLock = null) => async (userMsg) => {
|
|
75
41
|
if (msg) {
|
|
76
|
-
debug('rabbit acking message', { deliveryTag: msg.fields.deliveryTag });
|
|
77
42
|
await channel.ack(msg);
|
|
78
43
|
const { properties: { headers } } = msg;
|
|
79
44
|
const timestamp = headers?.creationTimestamp;
|
|
@@ -106,30 +71,25 @@ class RabbitMq {
|
|
|
106
71
|
: 1,
|
|
107
72
|
});
|
|
108
73
|
}
|
|
109
|
-
debug('rabbit nacking message', { deliveryTag: msg.fields.deliveryTag });
|
|
110
74
|
await channel.ack(msg);
|
|
111
75
|
}
|
|
112
76
|
else {
|
|
113
77
|
logger_1.default.error('no channel or msg', {
|
|
78
|
+
channel: channel ? channel.name : '',
|
|
114
79
|
msg,
|
|
115
80
|
});
|
|
116
81
|
}
|
|
117
82
|
};
|
|
118
83
|
this.em = new events_1.EventEmitter();
|
|
119
84
|
this.channel = null;
|
|
120
|
-
this.
|
|
121
|
-
this.
|
|
122
|
-
[types_1.ConnectionPurpose.Consume]: { connection: null, creatingConnection: false },
|
|
123
|
-
[types_1.ConnectionPurpose.Publish]: { connection: null, creatingConnection: false },
|
|
124
|
-
};
|
|
85
|
+
this.connection = null;
|
|
86
|
+
this.creatingConnection = false;
|
|
125
87
|
this.exchanges = {};
|
|
126
88
|
this.queues = {};
|
|
127
|
-
this.queueSetupPromises = {};
|
|
128
|
-
this.consumers = [];
|
|
129
89
|
this.options = options;
|
|
130
|
-
this.redisClient = redisConfig &&
|
|
90
|
+
this.redisClient = redisConfig && redis_1.default(redisConfig);
|
|
131
91
|
if (this.redisClient) {
|
|
132
|
-
this.redisLock =
|
|
92
|
+
this.redisLock = util_1.promisify(redis_lock_1.default(this.redisClient));
|
|
133
93
|
}
|
|
134
94
|
this.consumersTags = [];
|
|
135
95
|
logger_1.default.info(`rabbit: [gracefully-shutdown] adding gracefully shutdown for process.pid ${process.pid}`);
|
|
@@ -142,31 +102,63 @@ class RabbitMq {
|
|
|
142
102
|
});
|
|
143
103
|
}
|
|
144
104
|
}
|
|
145
|
-
|
|
105
|
+
static parseMsg(msg) {
|
|
106
|
+
let { content } = msg;
|
|
107
|
+
content = content.toString();
|
|
108
|
+
try {
|
|
109
|
+
content = JSON.parse(content);
|
|
110
|
+
}
|
|
111
|
+
catch (e) { }
|
|
112
|
+
return {
|
|
113
|
+
...msg,
|
|
114
|
+
content,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
static validateName(type, name) {
|
|
118
|
+
if (!name || name === '') {
|
|
119
|
+
throw new rabbitError_1.default(`error while using ${type} with no name`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
static getPublishOptions(customHeaders = {}) {
|
|
123
|
+
const trace = zehut_1.getCurrentPayload();
|
|
124
|
+
const user = trace?.context?.get(consts_1.USER_OBJECT);
|
|
125
|
+
const traceId = trace?.context?.get(consts_1.TRACING_HEADER);
|
|
126
|
+
const outbreakTrace = zehut_1.outbreak.getCurrentContext();
|
|
127
|
+
return {
|
|
128
|
+
timestamp: moment_1.default().unix(),
|
|
129
|
+
timeout: PUBLISH_TIMEOUT,
|
|
130
|
+
headers: {
|
|
131
|
+
creationTimestamp: moment_1.default().valueOf(),
|
|
132
|
+
...customHeaders,
|
|
133
|
+
[consts_1.USER_TRACING_HEADER]: user?.id,
|
|
134
|
+
[consts_1.TRACING_HEADER]: traceId || outbreakTrace?.context?.get(consts_1.TRACING_HEADER),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async getConnection() {
|
|
146
139
|
return new Promise(async (resolve, reject) => {
|
|
147
|
-
let { connection, creatingConnection } = this.connectionsMap[connectionPurpose];
|
|
148
140
|
if (this.blockReconnect) {
|
|
149
141
|
debug('rabbit: block reconnect');
|
|
150
142
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
151
143
|
// @ts-ignore
|
|
152
144
|
return resolve();
|
|
153
145
|
}
|
|
154
|
-
if (connection !== null) {
|
|
155
|
-
if (this.options?.disableReconnect || connection?.isConnected()) {
|
|
146
|
+
if (this.connection !== null) {
|
|
147
|
+
if (this.options?.disableReconnect || this.connection?.isConnected()) {
|
|
156
148
|
debug('rabbit: connection - is connected');
|
|
157
149
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
158
150
|
// @ts-ignore
|
|
159
|
-
return resolve(connection);
|
|
151
|
+
return resolve(this.connection);
|
|
160
152
|
}
|
|
161
153
|
debug('rabbit: connection - reconnecting');
|
|
162
154
|
}
|
|
163
|
-
if (creatingConnection) {
|
|
155
|
+
if (this.creatingConnection) {
|
|
164
156
|
debug('rabbit: creating connection emi');
|
|
165
157
|
this.em.once(consts_1.CONNECTION_CREATED_CONST, resolve);
|
|
166
158
|
this.em.once(consts_1.CONNECTION_FAILED_CONST, reject);
|
|
167
159
|
return;
|
|
168
160
|
}
|
|
169
|
-
this.
|
|
161
|
+
this.creatingConnection = true;
|
|
170
162
|
let isResolved = false;
|
|
171
163
|
// It is import to use it as a function and not as a variable
|
|
172
164
|
// because of k8s changes the env variables
|
|
@@ -179,15 +171,11 @@ class RabbitMq {
|
|
|
179
171
|
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
180
172
|
};
|
|
181
173
|
const defaultUrls = findServers();
|
|
182
|
-
const
|
|
174
|
+
const connection = await amqp_connection_manager_1.connect(defaultUrls, {
|
|
183
175
|
findServers,
|
|
184
176
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return resolve(connection);
|
|
188
|
-
}
|
|
189
|
-
this.connectionsMap[connectionPurpose].connection = newConnection;
|
|
190
|
-
newConnection.on('error', (err) => {
|
|
177
|
+
this.connection = connection;
|
|
178
|
+
this.connection.on('error', (err) => {
|
|
191
179
|
logger_1.default.error('rabbit: connection error', { err });
|
|
192
180
|
if (!isResolved) {
|
|
193
181
|
isResolved = true;
|
|
@@ -195,8 +183,7 @@ class RabbitMq {
|
|
|
195
183
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
196
184
|
}
|
|
197
185
|
});
|
|
198
|
-
|
|
199
|
-
this.consumersTags = [];
|
|
186
|
+
this.connection.on('connectFailed', (err) => {
|
|
200
187
|
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
201
188
|
if (!isResolved) {
|
|
202
189
|
isResolved = true;
|
|
@@ -204,9 +191,10 @@ class RabbitMq {
|
|
|
204
191
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
205
192
|
}
|
|
206
193
|
});
|
|
207
|
-
|
|
208
|
-
this.consumersTags = [];
|
|
194
|
+
this.connection.on('disconnect', ({ err }) => {
|
|
209
195
|
debug('rabbit: connection closed');
|
|
196
|
+
this.exchanges = {};
|
|
197
|
+
this.queues = {};
|
|
210
198
|
if (this.options?.disableReconnect) {
|
|
211
199
|
logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
212
200
|
this.blockReconnect = true;
|
|
@@ -215,99 +203,95 @@ class RabbitMq {
|
|
|
215
203
|
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
216
204
|
}
|
|
217
205
|
});
|
|
218
|
-
|
|
206
|
+
this.connection.once('connect', async () => {
|
|
219
207
|
debug('rabbit: connection established');
|
|
220
|
-
this.
|
|
221
|
-
this.
|
|
208
|
+
await this.loadConsumers();
|
|
209
|
+
this.creatingConnection = false;
|
|
210
|
+
this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
|
|
222
211
|
isResolved = true;
|
|
223
|
-
resolve(
|
|
212
|
+
resolve(connection);
|
|
224
213
|
});
|
|
225
214
|
});
|
|
226
215
|
}
|
|
227
|
-
async getNewChannel({ name =
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
238
|
-
}
|
|
239
|
-
const channel = connection.createChannel({ ...options });
|
|
240
|
-
(0, events_1.once)(channel, 'close').then((args) => {
|
|
241
|
-
logger_1.default.error(`rabbit: channel ${name} closed`);
|
|
242
|
-
onClose?.(args);
|
|
243
|
-
});
|
|
244
|
-
try {
|
|
245
|
-
await (0, events_1.once)(channel, 'connect');
|
|
246
|
-
debug(`rabbit: channel ${name} CONNECTED`);
|
|
247
|
-
return channel;
|
|
248
|
-
}
|
|
249
|
-
catch (err) {
|
|
250
|
-
logger_1.default.error(`rabbit: channel error ${name} error`, { err });
|
|
251
|
-
throw err;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
async assertChannel({ force = false, connectionPurpose = types_1.ConnectionPurpose.Consume }) {
|
|
255
|
-
if (!this.publishChannelSetupPromise) {
|
|
256
|
-
this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
|
|
257
|
-
if (this.channel && !force) {
|
|
258
|
-
return resolve(this.channel);
|
|
259
|
-
}
|
|
260
|
-
try {
|
|
261
|
-
const channel = await this.getNewChannel({ connectionPurpose });
|
|
262
|
-
channel.on('error', (err) => {
|
|
263
|
-
logger_1.default.error('rabbit: channel error', { err });
|
|
264
|
-
});
|
|
265
|
-
this.channel = channel;
|
|
266
|
-
resolve(channel);
|
|
216
|
+
async getNewChannel({ name = utils_1.rand().toString(), onClose = null } = {}) {
|
|
217
|
+
return new Promise(async (resolve, reject) => {
|
|
218
|
+
const connection = await this.getConnection();
|
|
219
|
+
const channel = connection.createChannel({});
|
|
220
|
+
let isResolved = false;
|
|
221
|
+
channel.on('error', (err) => {
|
|
222
|
+
logger_1.default.error(`rabbit: channel ${name} error`, { err });
|
|
223
|
+
if (!isResolved) {
|
|
224
|
+
isResolved = true;
|
|
225
|
+
reject(err);
|
|
267
226
|
}
|
|
268
|
-
|
|
269
|
-
|
|
227
|
+
});
|
|
228
|
+
channel.on('close', (...args) => {
|
|
229
|
+
logger_1.default.error(`rabbit: channel ${name} closed`, { args });
|
|
230
|
+
if (onClose) {
|
|
231
|
+
onClose(args);
|
|
270
232
|
}
|
|
271
233
|
});
|
|
272
|
-
|
|
273
|
-
|
|
234
|
+
channel.once('connect', () => {
|
|
235
|
+
debug(`rabbit: channel ${name} CONNECTED`);
|
|
236
|
+
isResolved = true;
|
|
237
|
+
resolve(channel);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async assertChannel({ force = false } = {}) {
|
|
242
|
+
return new Promise(async (resolve, reject) => {
|
|
243
|
+
if (this.channel && !force) {
|
|
244
|
+
return resolve(this.channel);
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const channel = await this.getNewChannel({});
|
|
248
|
+
channel.on('error', (err) => {
|
|
249
|
+
logger_1.default.error('rabbit: channel error', { err });
|
|
250
|
+
});
|
|
251
|
+
this.channel = channel;
|
|
252
|
+
resolve(channel);
|
|
253
|
+
}
|
|
254
|
+
catch (e) {
|
|
255
|
+
reject(e);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
274
258
|
}
|
|
275
259
|
async assertExchange(exchangeName, options) {
|
|
276
|
-
const channel = await this.assertChannel(
|
|
260
|
+
const channel = await this.assertChannel();
|
|
277
261
|
if (this.exchanges[exchangeName]) {
|
|
278
262
|
return this.exchanges[exchangeName];
|
|
279
263
|
}
|
|
280
|
-
const exchange = await
|
|
264
|
+
const exchange = await utils_1.assertExchangeFanout(channel, exchangeName);
|
|
281
265
|
this.exchanges[exchangeName] = exchange;
|
|
282
266
|
return exchange;
|
|
283
267
|
}
|
|
284
|
-
async getQueueLength(queue
|
|
268
|
+
async getQueueLength(queue) {
|
|
285
269
|
RabbitMq.validateName('queue', queue);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
throw new Error('channel is not defined');
|
|
290
|
-
}
|
|
291
|
-
debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
|
|
292
|
-
return channel?.checkQueue(queue);
|
|
270
|
+
const channel = await this.assertChannel();
|
|
271
|
+
debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
|
|
272
|
+
return channel.checkQueue(queue);
|
|
293
273
|
}
|
|
294
|
-
async deleteQueue(queue
|
|
274
|
+
async deleteQueue(queue) {
|
|
295
275
|
RabbitMq.validateName('queue', queue);
|
|
296
|
-
const channel = await this.assertChannel(
|
|
276
|
+
const channel = await this.assertChannel();
|
|
297
277
|
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
298
278
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
299
279
|
debug('queue deleted', deleteQueueRes);
|
|
300
280
|
return deleteQueueRes;
|
|
301
281
|
}
|
|
302
|
-
async bindQueue(queue, exchange
|
|
303
|
-
const channel = await this.assertChannel(
|
|
282
|
+
async bindQueue(queue, exchange) {
|
|
283
|
+
const channel = await this.assertChannel();
|
|
304
284
|
await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
305
285
|
return channel.bindQueue(queue, exchange, '');
|
|
306
286
|
}
|
|
307
|
-
async
|
|
308
|
-
let queue;
|
|
287
|
+
async assertQueue(queueName, options) {
|
|
288
|
+
let queue = null;
|
|
289
|
+
RabbitMq.validateName('queue', queueName);
|
|
290
|
+
if (this.queues[queueName]) {
|
|
291
|
+
return this.queues[queueName];
|
|
292
|
+
}
|
|
309
293
|
try {
|
|
310
|
-
const channel = await this.assertChannel(
|
|
294
|
+
const channel = await this.assertChannel();
|
|
311
295
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
312
296
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
313
297
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -317,11 +301,11 @@ class RabbitMq {
|
|
|
317
301
|
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
318
302
|
if (!this.options?.dontRetryAssert) {
|
|
319
303
|
debug('retrying assertQueue', { queueName });
|
|
320
|
-
const channel = await this.assertChannel({ force: true
|
|
321
|
-
await this.deleteQueue(queueName
|
|
322
|
-
debug('
|
|
304
|
+
const channel = await this.assertChannel({ force: true });
|
|
305
|
+
await this.deleteQueue(queueName);
|
|
306
|
+
debug('1assertQueue->channel.addSetup', { queueName });
|
|
323
307
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
324
|
-
debug('
|
|
308
|
+
debug('1assertQueue->channel.assertQueue', { queueName });
|
|
325
309
|
queue = await channel.assertQueue(queueName, options);
|
|
326
310
|
}
|
|
327
311
|
else {
|
|
@@ -331,31 +315,25 @@ class RabbitMq {
|
|
|
331
315
|
this.queues[queueName] = queueName;
|
|
332
316
|
return queue;
|
|
333
317
|
}
|
|
334
|
-
async assertQueue(queueName, connectionPurpose, options) {
|
|
335
|
-
RabbitMq.validateName('queue', queueName);
|
|
336
|
-
if (this.queues[queueName]) {
|
|
337
|
-
delete this.queueSetupPromises[queueName];
|
|
338
|
-
return this.queues[queueName];
|
|
339
|
-
}
|
|
340
|
-
if (this.queueSetupPromises[queueName]) {
|
|
341
|
-
return this.queueSetupPromises[queueName];
|
|
342
|
-
}
|
|
343
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName, connectionPurpose, options);
|
|
344
|
-
return this.queueSetupPromises[queueName];
|
|
345
|
-
}
|
|
346
318
|
saveConsumer(queue, callback, options) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
319
|
+
this.consumers.push({
|
|
320
|
+
queue,
|
|
321
|
+
callback,
|
|
322
|
+
options,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
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)));
|
|
355
330
|
}
|
|
356
331
|
}
|
|
357
332
|
async consume(queue, callback, options) {
|
|
358
|
-
|
|
333
|
+
if (this.connection && !this.creatingConnection) {
|
|
334
|
+
this.consumeFromRabbit(queue, callback, options);
|
|
335
|
+
}
|
|
336
|
+
return this.saveConsumer(queue, callback, options);
|
|
359
337
|
}
|
|
360
338
|
async lockRedisIfNeeded(msg, options) {
|
|
361
339
|
const { properties: { headers } } = msg;
|
|
@@ -374,8 +352,6 @@ class RabbitMq {
|
|
|
374
352
|
async consumeFromRabbit(queue, callback, options) {
|
|
375
353
|
const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
|
|
376
354
|
RabbitMq.validateName('queue', queue);
|
|
377
|
-
this.saveConsumer(queue, callback, options);
|
|
378
|
-
const uniqueId = (0, node_crypto_1.randomUUID)();
|
|
379
355
|
const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
|
|
380
356
|
if (useConsumeWithLock) {
|
|
381
357
|
if (!this.redisLock) {
|
|
@@ -383,11 +359,11 @@ class RabbitMq {
|
|
|
383
359
|
}
|
|
384
360
|
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
385
361
|
}
|
|
386
|
-
const channel = await this.getNewChannel({
|
|
387
|
-
return channel.addSetup(async (
|
|
388
|
-
await
|
|
389
|
-
await
|
|
390
|
-
const { consumerTag } = await
|
|
362
|
+
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) => {
|
|
391
367
|
if (!msg) {
|
|
392
368
|
return null;
|
|
393
369
|
}
|
|
@@ -395,7 +371,7 @@ class RabbitMq {
|
|
|
395
371
|
const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
|
|
396
372
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
397
373
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
398
|
-
const trace =
|
|
374
|
+
const trace = zehut_1.newTrace(zehut_1.traceTypes.RABBIT);
|
|
399
375
|
// setting also outbreak trace as part of legacy code
|
|
400
376
|
const outbreakTrace = zehut_1.outbreak.newTrace(zehut_1.traceTypes.RABBIT);
|
|
401
377
|
// enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
|
|
@@ -403,13 +379,13 @@ class RabbitMq {
|
|
|
403
379
|
if (userId && enableRabbitTrace) {
|
|
404
380
|
try {
|
|
405
381
|
await Promise.all([
|
|
406
|
-
|
|
407
|
-
|
|
382
|
+
zehut_1.createOrSetRabbitTrace(trace, userId),
|
|
383
|
+
zehut_1.createOrSetRabbitTrace(outbreakTrace, userId),
|
|
408
384
|
]);
|
|
409
385
|
}
|
|
410
386
|
catch (e) {
|
|
411
387
|
logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
412
|
-
|
|
388
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
413
389
|
}
|
|
414
390
|
}
|
|
415
391
|
if (traceId) {
|
|
@@ -422,30 +398,13 @@ class RabbitMq {
|
|
|
422
398
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
423
399
|
if (!shouldConsume) {
|
|
424
400
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
425
|
-
return this.ack(
|
|
401
|
+
return this.ack(channel, msg)(msg);
|
|
426
402
|
}
|
|
427
|
-
let messageAcked = false;
|
|
428
|
-
// setting the localAck function to be used in the callback
|
|
429
|
-
const localAck = async () => {
|
|
430
|
-
if (messageAcked) {
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
messageAcked = true;
|
|
434
|
-
return this.ack(confirmChannel, msg, true, releaseLock)(msg);
|
|
435
|
-
};
|
|
436
|
-
const localNack = async (_, nackOptions = {}) => {
|
|
437
|
-
if (messageAcked) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
debug('rabbit localNack', { messageAcked, uniqueId, deliveryTag: msg.fields.deliveryTag });
|
|
441
|
-
messageAcked = true;
|
|
442
|
-
return this.nack(confirmChannel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg, nackOptions);
|
|
443
|
-
};
|
|
444
403
|
try {
|
|
445
|
-
await callback(parsedMessage,
|
|
404
|
+
await callback(parsedMessage, this.ack(channel, msg, true, releaseLock), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock));
|
|
446
405
|
}
|
|
447
406
|
catch (e) {
|
|
448
|
-
await
|
|
407
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
449
408
|
}
|
|
450
409
|
}, types_1.CONSUMER_DEFAULT_OPTIONS);
|
|
451
410
|
if (!consumerTag) {
|
|
@@ -453,7 +412,7 @@ class RabbitMq {
|
|
|
453
412
|
}
|
|
454
413
|
else {
|
|
455
414
|
logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
456
|
-
this.consumersTags.push([
|
|
415
|
+
this.consumersTags.push([c, consumerTag]);
|
|
457
416
|
}
|
|
458
417
|
});
|
|
459
418
|
}
|
|
@@ -462,10 +421,9 @@ class RabbitMq {
|
|
|
462
421
|
RabbitMq.validateName('exchange', exchange);
|
|
463
422
|
RabbitMq.validateName('queue', queue);
|
|
464
423
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
465
|
-
await this.
|
|
466
|
-
const channel = await this.getNewChannel({ name: `consume - exchange - ${exchange} -queue - ${queue}`, connectionPurpose: types_1.ConnectionPurpose.Consume });
|
|
424
|
+
const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
467
425
|
return channel.addSetup(async (c) => {
|
|
468
|
-
const assertExchange = await
|
|
426
|
+
const assertExchange = await utils_1.assertExchangeFanout(c, exchange);
|
|
469
427
|
await c.assertQueue(queue);
|
|
470
428
|
this.exchanges[exchange] = assertExchange;
|
|
471
429
|
await c.prefetch(limit, true);
|
|
@@ -476,64 +434,36 @@ class RabbitMq {
|
|
|
476
434
|
});
|
|
477
435
|
}
|
|
478
436
|
async publish(exchange, content, customHeaders) {
|
|
479
|
-
return
|
|
437
|
+
return utils_1.wrapSetImmediate(async () => {
|
|
480
438
|
RabbitMq.validateName('exchange', exchange);
|
|
481
|
-
const channel = await this.assertChannel(
|
|
482
|
-
await this.assertExchange(exchange
|
|
439
|
+
const channel = await this.assertChannel();
|
|
440
|
+
await this.assertExchange(exchange);
|
|
483
441
|
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
484
442
|
});
|
|
485
443
|
}
|
|
486
|
-
async sendToQueue(queue, content, options, customHeaders) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
504
|
-
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
505
|
-
return res;
|
|
506
|
-
}
|
|
507
|
-
catch (e) {
|
|
508
|
-
const isConnected = await this.isConnected(types_1.ConnectionPurpose.Publish);
|
|
509
|
-
logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
510
|
-
throw e;
|
|
444
|
+
async sendToQueue(queue, content, options, customHeaders, isBlocking) {
|
|
445
|
+
const callback = async () => {
|
|
446
|
+
try {
|
|
447
|
+
RabbitMq.validateName('queue', queue);
|
|
448
|
+
await this.assertChannel();
|
|
449
|
+
await this.assertQueue(queue, options);
|
|
450
|
+
const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
451
|
+
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
452
|
+
return res;
|
|
453
|
+
}
|
|
454
|
+
catch (e) {
|
|
455
|
+
logger_1.default.error(`rabbit: failed to send to queue ${queue}`, { e });
|
|
456
|
+
throw e;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
if (isBlocking) {
|
|
460
|
+
return callback();
|
|
511
461
|
}
|
|
462
|
+
return utils_1.wrapSetImmediate(callback);
|
|
512
463
|
}
|
|
513
|
-
async isConnected(
|
|
514
|
-
const connection = await this.getConnection(
|
|
515
|
-
|
|
516
|
-
logger_1.default.error('rabbit: isConnected - false');
|
|
517
|
-
return false;
|
|
518
|
-
}
|
|
519
|
-
const isConnected = connection.isConnected();
|
|
520
|
-
if (!isConnected) {
|
|
521
|
-
logger_1.default.error('rabbit: isConnected - false');
|
|
522
|
-
return false;
|
|
523
|
-
}
|
|
524
|
-
const channel = await this.assertChannel({ connectionPurpose });
|
|
525
|
-
try {
|
|
526
|
-
await Promise.all([
|
|
527
|
-
channel.waitForConnect(),
|
|
528
|
-
...this.consumers.map((c) => channel.checkQueue(c.queue)),
|
|
529
|
-
]);
|
|
530
|
-
}
|
|
531
|
-
catch (e) {
|
|
532
|
-
logger_1.default.error('rabbit: isConnected - false');
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
logger_1.default.info('rabbit: isConnected - true');
|
|
536
|
-
return true;
|
|
464
|
+
async isConnected() {
|
|
465
|
+
const connection = await this.getConnection();
|
|
466
|
+
return connection.isConnected();
|
|
537
467
|
}
|
|
538
468
|
async gracefulShutdown(signal) {
|
|
539
469
|
const tagsNumber = this.consumersTags.length;
|
package/dist/lib/redis.d.ts
CHANGED