@autofleet/rabbit 3.2.2-2.beta-0 → 3.2.2
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 -244
- 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 -244
- 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,35 +102,64 @@ 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
|
-
// It is import to use it as a function and not as a variable
|
|
172
|
-
// because of k8s changes the env variables
|
|
173
|
-
// and we want to use the new values
|
|
174
163
|
const findServers = () => {
|
|
175
164
|
const userName = process.env.RABBITMQ_USERNAME || 'guest';
|
|
176
165
|
const password = process.env.RABBITMQ_PASSWORD || 'guest';
|
|
@@ -179,15 +168,11 @@ class RabbitMq {
|
|
|
179
168
|
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
180
169
|
};
|
|
181
170
|
const defaultUrls = findServers();
|
|
182
|
-
const
|
|
171
|
+
const connection = await amqp_connection_manager_1.connect(defaultUrls, {
|
|
183
172
|
findServers,
|
|
184
173
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return resolve(connection);
|
|
188
|
-
}
|
|
189
|
-
this.connectionsMap[connectionPurpose].connection = newConnection;
|
|
190
|
-
newConnection.on('error', (err) => {
|
|
174
|
+
this.connection = connection;
|
|
175
|
+
this.connection.on('error', (err) => {
|
|
191
176
|
logger_1.default.error('rabbit: connection error', { err });
|
|
192
177
|
if (!isResolved) {
|
|
193
178
|
isResolved = true;
|
|
@@ -195,8 +180,7 @@ class RabbitMq {
|
|
|
195
180
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
196
181
|
}
|
|
197
182
|
});
|
|
198
|
-
|
|
199
|
-
this.consumersTags = [];
|
|
183
|
+
this.connection.on('connectFailed', (err) => {
|
|
200
184
|
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
201
185
|
if (!isResolved) {
|
|
202
186
|
isResolved = true;
|
|
@@ -204,9 +188,10 @@ class RabbitMq {
|
|
|
204
188
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
205
189
|
}
|
|
206
190
|
});
|
|
207
|
-
|
|
208
|
-
this.consumersTags = [];
|
|
191
|
+
this.connection.on('disconnect', ({ err }) => {
|
|
209
192
|
debug('rabbit: connection closed');
|
|
193
|
+
this.exchanges = {};
|
|
194
|
+
this.queues = {};
|
|
210
195
|
if (this.options?.disableReconnect) {
|
|
211
196
|
logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
|
|
212
197
|
this.blockReconnect = true;
|
|
@@ -215,99 +200,95 @@ class RabbitMq {
|
|
|
215
200
|
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
216
201
|
}
|
|
217
202
|
});
|
|
218
|
-
|
|
203
|
+
this.connection.once('connect', async () => {
|
|
219
204
|
debug('rabbit: connection established');
|
|
220
|
-
this.
|
|
221
|
-
this.
|
|
205
|
+
await this.loadConsumers();
|
|
206
|
+
this.creatingConnection = false;
|
|
207
|
+
this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
|
|
222
208
|
isResolved = true;
|
|
223
|
-
resolve(
|
|
209
|
+
resolve(connection);
|
|
224
210
|
});
|
|
225
211
|
});
|
|
226
212
|
}
|
|
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);
|
|
213
|
+
async getNewChannel({ name = utils_1.rand().toString(), onClose = null } = {}) {
|
|
214
|
+
return new Promise(async (resolve, reject) => {
|
|
215
|
+
const connection = await this.getConnection();
|
|
216
|
+
const channel = connection.createChannel({});
|
|
217
|
+
let isResolved = false;
|
|
218
|
+
channel.on('error', (err) => {
|
|
219
|
+
logger_1.default.error(`rabbit: channel ${name} error`, { err });
|
|
220
|
+
if (!isResolved) {
|
|
221
|
+
isResolved = true;
|
|
222
|
+
reject(err);
|
|
267
223
|
}
|
|
268
|
-
|
|
269
|
-
|
|
224
|
+
});
|
|
225
|
+
channel.on('close', (...args) => {
|
|
226
|
+
logger_1.default.error(`rabbit: channel ${name} closed`, { args });
|
|
227
|
+
if (onClose) {
|
|
228
|
+
onClose(args);
|
|
270
229
|
}
|
|
271
230
|
});
|
|
272
|
-
|
|
273
|
-
|
|
231
|
+
channel.once('connect', () => {
|
|
232
|
+
debug(`rabbit: channel ${name} CONNECTED`);
|
|
233
|
+
isResolved = true;
|
|
234
|
+
resolve(channel);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async assertChannel({ force = false } = {}) {
|
|
239
|
+
return new Promise(async (resolve, reject) => {
|
|
240
|
+
if (this.channel && !force) {
|
|
241
|
+
return resolve(this.channel);
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const channel = await this.getNewChannel({});
|
|
245
|
+
channel.on('error', (err) => {
|
|
246
|
+
logger_1.default.error('rabbit: channel error', { err });
|
|
247
|
+
});
|
|
248
|
+
this.channel = channel;
|
|
249
|
+
resolve(channel);
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
reject(e);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
274
255
|
}
|
|
275
256
|
async assertExchange(exchangeName, options) {
|
|
276
|
-
const channel = await this.assertChannel(
|
|
257
|
+
const channel = await this.assertChannel();
|
|
277
258
|
if (this.exchanges[exchangeName]) {
|
|
278
259
|
return this.exchanges[exchangeName];
|
|
279
260
|
}
|
|
280
|
-
const exchange = await
|
|
261
|
+
const exchange = await utils_1.assertExchangeFanout(channel, exchangeName);
|
|
281
262
|
this.exchanges[exchangeName] = exchange;
|
|
282
263
|
return exchange;
|
|
283
264
|
}
|
|
284
|
-
async getQueueLength(queue
|
|
265
|
+
async getQueueLength(queue) {
|
|
285
266
|
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);
|
|
267
|
+
const channel = await this.assertChannel();
|
|
268
|
+
debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
|
|
269
|
+
return channel.checkQueue(queue);
|
|
293
270
|
}
|
|
294
|
-
async deleteQueue(queue
|
|
271
|
+
async deleteQueue(queue) {
|
|
295
272
|
RabbitMq.validateName('queue', queue);
|
|
296
|
-
const channel = await this.assertChannel(
|
|
273
|
+
const channel = await this.assertChannel();
|
|
297
274
|
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
298
275
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
299
276
|
debug('queue deleted', deleteQueueRes);
|
|
300
277
|
return deleteQueueRes;
|
|
301
278
|
}
|
|
302
|
-
async bindQueue(queue, exchange
|
|
303
|
-
const channel = await this.assertChannel(
|
|
279
|
+
async bindQueue(queue, exchange) {
|
|
280
|
+
const channel = await this.assertChannel();
|
|
304
281
|
await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
305
282
|
return channel.bindQueue(queue, exchange, '');
|
|
306
283
|
}
|
|
307
|
-
async
|
|
308
|
-
let queue;
|
|
284
|
+
async assertQueue(queueName, options) {
|
|
285
|
+
let queue = null;
|
|
286
|
+
RabbitMq.validateName('queue', queueName);
|
|
287
|
+
if (this.queues[queueName]) {
|
|
288
|
+
return this.queues[queueName];
|
|
289
|
+
}
|
|
309
290
|
try {
|
|
310
|
-
const channel = await this.assertChannel(
|
|
291
|
+
const channel = await this.assertChannel();
|
|
311
292
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
312
293
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
313
294
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
@@ -317,11 +298,11 @@ class RabbitMq {
|
|
|
317
298
|
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
318
299
|
if (!this.options?.dontRetryAssert) {
|
|
319
300
|
debug('retrying assertQueue', { queueName });
|
|
320
|
-
const channel = await this.assertChannel({ force: true
|
|
321
|
-
await this.deleteQueue(queueName
|
|
322
|
-
debug('
|
|
301
|
+
const channel = await this.assertChannel({ force: true });
|
|
302
|
+
await this.deleteQueue(queueName);
|
|
303
|
+
debug('1assertQueue->channel.addSetup', { queueName });
|
|
323
304
|
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, options));
|
|
324
|
-
debug('
|
|
305
|
+
debug('1assertQueue->channel.assertQueue', { queueName });
|
|
325
306
|
queue = await channel.assertQueue(queueName, options);
|
|
326
307
|
}
|
|
327
308
|
else {
|
|
@@ -331,31 +312,25 @@ class RabbitMq {
|
|
|
331
312
|
this.queues[queueName] = queueName;
|
|
332
313
|
return queue;
|
|
333
314
|
}
|
|
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
315
|
saveConsumer(queue, callback, options) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
316
|
+
this.consumers.push({
|
|
317
|
+
queue,
|
|
318
|
+
callback,
|
|
319
|
+
options,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
async loadConsumers() {
|
|
323
|
+
debug('rabbit: loading consumers', { consumers: this.consumers.length });
|
|
324
|
+
if (this.consumers.length > 0) {
|
|
325
|
+
await Promise.all(this.consumers.map((consumer) => this
|
|
326
|
+
.consumeFromRabbit(consumer.queue, consumer.callback, consumer.options)));
|
|
355
327
|
}
|
|
356
328
|
}
|
|
357
329
|
async consume(queue, callback, options) {
|
|
358
|
-
|
|
330
|
+
if (this.connection && !this.creatingConnection) {
|
|
331
|
+
this.consumeFromRabbit(queue, callback, options);
|
|
332
|
+
}
|
|
333
|
+
return this.saveConsumer(queue, callback, options);
|
|
359
334
|
}
|
|
360
335
|
async lockRedisIfNeeded(msg, options) {
|
|
361
336
|
const { properties: { headers } } = msg;
|
|
@@ -374,8 +349,6 @@ class RabbitMq {
|
|
|
374
349
|
async consumeFromRabbit(queue, callback, options) {
|
|
375
350
|
const optionsWithDefaults = { ...consts_1.DEFAULT_OPTIONS, ...options };
|
|
376
351
|
RabbitMq.validateName('queue', queue);
|
|
377
|
-
this.saveConsumer(queue, callback, options);
|
|
378
|
-
const uniqueId = (0, node_crypto_1.randomUUID)();
|
|
379
352
|
const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
|
|
380
353
|
if (useConsumeWithLock) {
|
|
381
354
|
if (!this.redisLock) {
|
|
@@ -383,11 +356,11 @@ class RabbitMq {
|
|
|
383
356
|
}
|
|
384
357
|
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
385
358
|
}
|
|
386
|
-
const channel = await this.getNewChannel({
|
|
387
|
-
return channel.addSetup(async (
|
|
388
|
-
await
|
|
389
|
-
await
|
|
390
|
-
const { consumerTag } = await
|
|
359
|
+
const channel = await this.getNewChannel({ name: `consume-queue-${queue}` });
|
|
360
|
+
return channel.addSetup(async (c) => {
|
|
361
|
+
await c.assertQueue(queue, options ? { messageTtl: options.messageTtl } : undefined);
|
|
362
|
+
await c.prefetch(limit, true);
|
|
363
|
+
const { consumerTag } = await c.consume(queue, async (msg) => {
|
|
391
364
|
if (!msg) {
|
|
392
365
|
return null;
|
|
393
366
|
}
|
|
@@ -395,7 +368,7 @@ class RabbitMq {
|
|
|
395
368
|
const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
|
|
396
369
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
397
370
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
398
|
-
const trace =
|
|
371
|
+
const trace = zehut_1.newTrace(zehut_1.traceTypes.RABBIT);
|
|
399
372
|
// setting also outbreak trace as part of legacy code
|
|
400
373
|
const outbreakTrace = zehut_1.outbreak.newTrace(zehut_1.traceTypes.RABBIT);
|
|
401
374
|
// enableRabbitTrace is a flag to protect from different flows that doesn't work with permission
|
|
@@ -403,13 +376,13 @@ class RabbitMq {
|
|
|
403
376
|
if (userId && enableRabbitTrace) {
|
|
404
377
|
try {
|
|
405
378
|
await Promise.all([
|
|
406
|
-
|
|
407
|
-
|
|
379
|
+
zehut_1.createOrSetRabbitTrace(trace, userId),
|
|
380
|
+
zehut_1.createOrSetRabbitTrace(outbreakTrace, userId),
|
|
408
381
|
]);
|
|
409
382
|
}
|
|
410
383
|
catch (e) {
|
|
411
384
|
logger_1.default.error('rabbit: failed to setRabbitTrace', { userId, e });
|
|
412
|
-
|
|
385
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
413
386
|
}
|
|
414
387
|
}
|
|
415
388
|
if (traceId) {
|
|
@@ -422,30 +395,13 @@ class RabbitMq {
|
|
|
422
395
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
423
396
|
if (!shouldConsume) {
|
|
424
397
|
await this.unlockRedisIfNeeded(releaseLock);
|
|
425
|
-
return this.ack(
|
|
398
|
+
return this.ack(channel, msg)(msg);
|
|
426
399
|
}
|
|
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
400
|
try {
|
|
445
|
-
await callback(parsedMessage,
|
|
401
|
+
await callback(parsedMessage, this.ack(channel, msg, true, releaseLock), this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock));
|
|
446
402
|
}
|
|
447
403
|
catch (e) {
|
|
448
|
-
await
|
|
404
|
+
await this.nack(channel, queue, optionsWithDefaults, { messageTtl: deadMessageTtl }, msg, releaseLock)(msg);
|
|
449
405
|
}
|
|
450
406
|
}, types_1.CONSUMER_DEFAULT_OPTIONS);
|
|
451
407
|
if (!consumerTag) {
|
|
@@ -453,7 +409,7 @@ class RabbitMq {
|
|
|
453
409
|
}
|
|
454
410
|
else {
|
|
455
411
|
logger_1.default.info(`rabbit: adding tag ${consumerTag} to the array.`);
|
|
456
|
-
this.consumersTags.push([
|
|
412
|
+
this.consumersTags.push([c, consumerTag]);
|
|
457
413
|
}
|
|
458
414
|
});
|
|
459
415
|
}
|
|
@@ -462,10 +418,9 @@ class RabbitMq {
|
|
|
462
418
|
RabbitMq.validateName('exchange', exchange);
|
|
463
419
|
RabbitMq.validateName('queue', queue);
|
|
464
420
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
465
|
-
await this.
|
|
466
|
-
const channel = await this.getNewChannel({ name: `consume - exchange - ${exchange} -queue - ${queue}`, connectionPurpose: types_1.ConnectionPurpose.Consume });
|
|
421
|
+
const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
467
422
|
return channel.addSetup(async (c) => {
|
|
468
|
-
const assertExchange = await
|
|
423
|
+
const assertExchange = await utils_1.assertExchangeFanout(c, exchange);
|
|
469
424
|
await c.assertQueue(queue);
|
|
470
425
|
this.exchanges[exchange] = assertExchange;
|
|
471
426
|
await c.prefetch(limit, true);
|
|
@@ -476,64 +431,36 @@ class RabbitMq {
|
|
|
476
431
|
});
|
|
477
432
|
}
|
|
478
433
|
async publish(exchange, content, customHeaders) {
|
|
479
|
-
return
|
|
434
|
+
return utils_1.wrapSetImmediate(async () => {
|
|
480
435
|
RabbitMq.validateName('exchange', exchange);
|
|
481
|
-
const channel = await this.assertChannel(
|
|
482
|
-
await this.assertExchange(exchange
|
|
436
|
+
const channel = await this.assertChannel();
|
|
437
|
+
await this.assertExchange(exchange);
|
|
483
438
|
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
484
439
|
});
|
|
485
440
|
}
|
|
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;
|
|
441
|
+
async sendToQueue(queue, content, options, customHeaders, isBlocking) {
|
|
442
|
+
const callback = async () => {
|
|
443
|
+
try {
|
|
444
|
+
RabbitMq.validateName('queue', queue);
|
|
445
|
+
await this.assertChannel();
|
|
446
|
+
await this.assertQueue(queue, options);
|
|
447
|
+
const res = await this.channel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
448
|
+
debug(`rabbit: sending to queue ${queue}`, { res });
|
|
449
|
+
return res;
|
|
450
|
+
}
|
|
451
|
+
catch (e) {
|
|
452
|
+
logger_1.default.error(`rabbit: failed to send to queue ${queue}`, { e });
|
|
453
|
+
throw e;
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
if (isBlocking) {
|
|
457
|
+
return callback();
|
|
511
458
|
}
|
|
459
|
+
return utils_1.wrapSetImmediate(callback);
|
|
512
460
|
}
|
|
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;
|
|
461
|
+
async isConnected() {
|
|
462
|
+
const connection = await this.getConnection();
|
|
463
|
+
return connection.isConnected();
|
|
537
464
|
}
|
|
538
465
|
async gracefulShutdown(signal) {
|
|
539
466
|
const tagsNumber = this.consumersTags.length;
|
package/dist/lib/redis.d.ts
CHANGED