@autofleet/rabbit 3.2.22-beta.5 → 3.2.23-beta.0.0
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 +14 -14
- package/dist/index.js +108 -93
- package/dist/lib/celery.d.ts +9 -0
- package/dist/lib/celery.js +54 -0
- package/dist/lib/consts.d.ts +1 -0
- package/dist/lib/consts.js +2 -1
- package/dist/lib/types.d.ts +3 -9
- package/dist/lib/types.js +1 -6
- package/dist/lib/utils.d.ts +2 -2
- package/package.json +5 -2
- package/src/index.ts +141 -118
- package/src/lib/celery.ts +89 -0
- package/src/lib/consts.ts +1 -0
- package/src/lib/types.ts +4 -11
- package/src/lib/utils.ts +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ 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 {
|
|
6
|
+
import { sendCeleryTaskViaHttp } from './lib/celery';
|
|
7
|
+
import { CallbackFunction, ConsumeMessageOrNull, ConsumeOptions, CustomMessageHeaders, QueuesCache, RedisLockType, ExchangesCache, QueueSetupPromisesDictionary, AssertExchangePromisesDictionary } from './lib/types';
|
|
7
8
|
export interface IAfRabbitMq {
|
|
8
9
|
ack: any;
|
|
9
10
|
nack: any;
|
|
@@ -37,12 +38,10 @@ type newChannelOpts = {
|
|
|
37
38
|
name?: string;
|
|
38
39
|
onClose?: null | ((args: any | null) => void);
|
|
39
40
|
options?: CreateChannelOpts | undefined;
|
|
40
|
-
connectionPurpose?: ConnectionPurpose;
|
|
41
41
|
};
|
|
42
42
|
type assertChannelOpts = {
|
|
43
43
|
channelName?: string;
|
|
44
44
|
force?: boolean;
|
|
45
|
-
connectionPurpose?: ConnectionPurpose;
|
|
46
45
|
};
|
|
47
46
|
declare class RabbitMq implements IAfRabbitMq {
|
|
48
47
|
static parseMsg(msg: any): any;
|
|
@@ -62,14 +61,13 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
62
61
|
channel: ChannelWrapper | null;
|
|
63
62
|
publishChannelSetupPromise: Promise<ChannelWrapper> | null;
|
|
64
63
|
blockReconnect: boolean | null | undefined;
|
|
65
|
-
|
|
66
|
-
[ConnectionPurpose.Consume]: ConnectionData;
|
|
67
|
-
[ConnectionPurpose.Publish]: ConnectionData;
|
|
68
|
-
};
|
|
64
|
+
connection: AmqpConnectionManager | null | undefined;
|
|
69
65
|
em: EventEmitter;
|
|
66
|
+
creatingConnection: boolean;
|
|
70
67
|
exchanges: ExchangesCache;
|
|
71
68
|
queues: QueuesCache;
|
|
72
69
|
queueSetupPromises: QueueSetupPromisesDictionary;
|
|
70
|
+
assertExchangePromises: AssertExchangePromisesDictionary;
|
|
73
71
|
options: AfRabbitOptions | undefined;
|
|
74
72
|
redisClient: any;
|
|
75
73
|
redisLock?: RedisLockType;
|
|
@@ -80,15 +78,16 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
80
78
|
private shouldConsumeMessageByTimestamp;
|
|
81
79
|
ack: (channel: ConfirmChannel, msg: ConsumeMessageOrNull, shouldUpdateRedisTimestamp?: boolean, releaseLock?: null) => (userMsg: ConsumeMessage) => Promise<any>;
|
|
82
80
|
nack: (channel: ConfirmChannel, queue: string, options: any, deadQueueOptions: Options.AssertQueue, msg: ConsumeMessageOrNull, releaseLock: any) => (userMsg: ConsumeMessageOrNull, { skipRetry, }?: NackOptions) => Promise<any>;
|
|
83
|
-
getConnection(
|
|
84
|
-
getNewChannel({ name, onClose, options
|
|
85
|
-
assertChannel({ force
|
|
81
|
+
getConnection(): Promise<AmqpConnectionManager>;
|
|
82
|
+
getNewChannel({ name, onClose, options }?: newChannelOpts): Promise<ChannelWrapper>;
|
|
83
|
+
assertChannel({ force }?: assertChannelOpts): Promise<ChannelWrapper>;
|
|
86
84
|
assertExchange(exchangeName: string, options?: any): Promise<any>;
|
|
87
|
-
getQueueLength(queue: string
|
|
85
|
+
getQueueLength(queue: string): Promise<Replies.AssertQueue>;
|
|
88
86
|
private deleteQueue;
|
|
89
|
-
bindQueue(queue: string, exchange: string
|
|
90
|
-
setupQueue(queueName: string,
|
|
91
|
-
|
|
87
|
+
bindQueue(queue: string, exchange: string): Promise<void>;
|
|
88
|
+
setupQueue(queueName: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue>;
|
|
89
|
+
static shouldUseQuorum(queueName: string): boolean;
|
|
90
|
+
assertQueue(queueName: string, options?: Options.AssertQueue): Promise<any>;
|
|
92
91
|
private saveConsumer;
|
|
93
92
|
consume(queue: string, callback: CallbackFunction, options?: ConsumeOptions): Promise<any>;
|
|
94
93
|
private lockRedisIfNeeded;
|
|
@@ -101,3 +100,4 @@ declare class RabbitMq implements IAfRabbitMq {
|
|
|
101
100
|
gracefulShutdown(signal: string): Promise<void>;
|
|
102
101
|
}
|
|
103
102
|
export default RabbitMq;
|
|
103
|
+
export { sendCeleryTaskViaHttp, };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.sendCeleryTaskViaHttp = void 0;
|
|
7
8
|
const events_1 = require("events");
|
|
8
9
|
const util_1 = require("util");
|
|
9
10
|
const moment_1 = __importDefault(require("moment"));
|
|
@@ -15,6 +16,8 @@ const logger_1 = __importDefault(require("./logger"));
|
|
|
15
16
|
const rabbitError_1 = __importDefault(require("./lib/rabbitError"));
|
|
16
17
|
const redis_1 = __importDefault(require("./lib/redis"));
|
|
17
18
|
const utils_1 = require("./lib/utils");
|
|
19
|
+
const celery_1 = require("./lib/celery");
|
|
20
|
+
Object.defineProperty(exports, "sendCeleryTaskViaHttp", { enumerable: true, get: function () { return celery_1.sendCeleryTaskViaHttp; } });
|
|
18
21
|
const consts_1 = require("./lib/consts");
|
|
19
22
|
const types_1 = require("./lib/types");
|
|
20
23
|
// const debug = nodeDebug('af-rabbitmq')
|
|
@@ -118,13 +121,12 @@ class RabbitMq {
|
|
|
118
121
|
this.em = new events_1.EventEmitter();
|
|
119
122
|
this.channel = null;
|
|
120
123
|
this.publishChannelSetupPromise = null;
|
|
121
|
-
this.
|
|
122
|
-
|
|
123
|
-
[types_1.ConnectionPurpose.Publish]: { connection: null, creatingConnection: false },
|
|
124
|
-
};
|
|
124
|
+
this.connection = null;
|
|
125
|
+
this.creatingConnection = false;
|
|
125
126
|
this.exchanges = {};
|
|
126
127
|
this.queues = {};
|
|
127
128
|
this.queueSetupPromises = {};
|
|
129
|
+
this.assertExchangePromises = {};
|
|
128
130
|
this.consumers = [];
|
|
129
131
|
this.options = options;
|
|
130
132
|
this.redisClient = redisConfig && (0, redis_1.default)(redisConfig);
|
|
@@ -142,32 +144,30 @@ class RabbitMq {
|
|
|
142
144
|
});
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
|
-
async getConnection(
|
|
147
|
+
async getConnection() {
|
|
146
148
|
return new Promise(async (resolve, reject) => {
|
|
147
|
-
const { connection, creatingConnection } = this.connectionsMap[connectionPurpose];
|
|
148
|
-
debug('rabbit: start getting new connection', { connection, creatingConnection, connectionPurpose });
|
|
149
149
|
if (this.blockReconnect) {
|
|
150
150
|
debug('rabbit: block reconnect');
|
|
151
151
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
152
152
|
// @ts-ignore
|
|
153
153
|
return resolve();
|
|
154
154
|
}
|
|
155
|
-
if (connection !== null) {
|
|
156
|
-
if (this.options?.disableReconnect || connection?.isConnected()) {
|
|
155
|
+
if (this.connection !== null) {
|
|
156
|
+
if (this.options?.disableReconnect || this.connection?.isConnected()) {
|
|
157
157
|
debug('rabbit: connection - is connected');
|
|
158
158
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
159
159
|
// @ts-ignore
|
|
160
|
-
return resolve(connection);
|
|
160
|
+
return resolve(this.connection);
|
|
161
161
|
}
|
|
162
162
|
debug('rabbit: connection - reconnecting');
|
|
163
163
|
}
|
|
164
|
-
if (creatingConnection) {
|
|
164
|
+
if (this.creatingConnection) {
|
|
165
165
|
debug('rabbit: creating connection emi');
|
|
166
166
|
this.em.once(consts_1.CONNECTION_CREATED_CONST, resolve);
|
|
167
167
|
this.em.once(consts_1.CONNECTION_FAILED_CONST, reject);
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
|
-
this.
|
|
170
|
+
this.creatingConnection = true;
|
|
171
171
|
let isResolved = false;
|
|
172
172
|
// It is import to use it as a function and not as a variable
|
|
173
173
|
// because of k8s changes the env variables
|
|
@@ -180,11 +180,11 @@ class RabbitMq {
|
|
|
180
180
|
return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
|
|
181
181
|
};
|
|
182
182
|
const defaultUrls = findServers();
|
|
183
|
-
const
|
|
183
|
+
const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
|
|
184
184
|
findServers,
|
|
185
185
|
});
|
|
186
|
-
this.
|
|
187
|
-
|
|
186
|
+
this.connection = connection;
|
|
187
|
+
this.connection.on('error', (err) => {
|
|
188
188
|
logger_1.default.error('rabbit: connection error', { err });
|
|
189
189
|
if (!isResolved) {
|
|
190
190
|
isResolved = true;
|
|
@@ -192,7 +192,7 @@ class RabbitMq {
|
|
|
192
192
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
193
193
|
}
|
|
194
194
|
});
|
|
195
|
-
|
|
195
|
+
this.connection.on('connectFailed', (err) => {
|
|
196
196
|
this.consumersTags = [];
|
|
197
197
|
logger_1.default.error('rabbit: connection connectFailed', { err });
|
|
198
198
|
if (!isResolved) {
|
|
@@ -201,7 +201,8 @@ class RabbitMq {
|
|
|
201
201
|
this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
|
-
|
|
204
|
+
this.connection.on('disconnect', ({ err }) => {
|
|
205
|
+
// this.channel = null;
|
|
205
206
|
this.consumersTags = [];
|
|
206
207
|
debug('rabbit: connection closed');
|
|
207
208
|
if (this.options?.disableReconnect) {
|
|
@@ -212,27 +213,24 @@ class RabbitMq {
|
|
|
212
213
|
logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
|
|
213
214
|
}
|
|
214
215
|
});
|
|
215
|
-
|
|
216
|
-
debug('rabbit: connection established'
|
|
217
|
-
this.
|
|
218
|
-
this.em.emit(consts_1.CONNECTION_CREATED_CONST,
|
|
216
|
+
this.connection.once('connect', async () => {
|
|
217
|
+
debug('rabbit: connection established');
|
|
218
|
+
this.creatingConnection = false;
|
|
219
|
+
this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
|
|
219
220
|
isResolved = true;
|
|
220
|
-
resolve(
|
|
221
|
+
resolve(connection);
|
|
221
222
|
});
|
|
222
223
|
});
|
|
223
224
|
}
|
|
224
|
-
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}
|
|
225
|
+
async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
|
|
225
226
|
let connection;
|
|
226
227
|
try {
|
|
227
|
-
connection = await this.getConnection(
|
|
228
|
+
connection = await this.getConnection();
|
|
228
229
|
}
|
|
229
230
|
catch (e) {
|
|
230
231
|
logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
|
|
231
232
|
throw e;
|
|
232
233
|
}
|
|
233
|
-
if (!connection) {
|
|
234
|
-
throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
|
|
235
|
-
}
|
|
236
234
|
const channel = connection.createChannel({ ...options });
|
|
237
235
|
(0, events_1.once)(channel, 'close').then((args) => {
|
|
238
236
|
logger_1.default.error(`rabbit: channel ${name} closed`);
|
|
@@ -248,16 +246,14 @@ class RabbitMq {
|
|
|
248
246
|
throw err;
|
|
249
247
|
}
|
|
250
248
|
}
|
|
251
|
-
async assertChannel({ force = false
|
|
252
|
-
debug('rabbit: start assert channel', { connectionPurpose, publishPromise: this.publishChannelSetupPromise, channel: this.channel });
|
|
249
|
+
async assertChannel({ force = false } = {}) {
|
|
253
250
|
if (!this.publishChannelSetupPromise) {
|
|
254
251
|
this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
|
|
255
252
|
if (this.channel && !force) {
|
|
256
253
|
return resolve(this.channel);
|
|
257
254
|
}
|
|
258
255
|
try {
|
|
259
|
-
const channel = await this.getNewChannel({
|
|
260
|
-
debug('rabbit: new channel got', { connectionPurpose, channel: this.channel });
|
|
256
|
+
const channel = await this.getNewChannel({});
|
|
261
257
|
channel.on('error', (err) => {
|
|
262
258
|
logger_1.default.error('rabbit: channel error', { err });
|
|
263
259
|
});
|
|
@@ -271,69 +267,90 @@ class RabbitMq {
|
|
|
271
267
|
}
|
|
272
268
|
return this.publishChannelSetupPromise;
|
|
273
269
|
}
|
|
274
|
-
async assertExchange(exchangeName, options
|
|
275
|
-
const channel = await this.assertChannel(
|
|
270
|
+
async assertExchange(exchangeName, options) {
|
|
271
|
+
const channel = await this.assertChannel();
|
|
276
272
|
if (this.exchanges[exchangeName]) {
|
|
273
|
+
delete this.assertExchangePromises[exchangeName];
|
|
277
274
|
return this.exchanges[exchangeName];
|
|
278
275
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
if (this.assertExchangePromises[exchangeName]) {
|
|
277
|
+
return this.assertExchangePromises[exchangeName];
|
|
278
|
+
}
|
|
279
|
+
this.assertExchangePromises[exchangeName] = (0, utils_1.assertExchangeFanout)(channel, exchangeName);
|
|
280
|
+
this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
|
|
281
|
+
return this.exchanges[exchangeName];
|
|
282
282
|
}
|
|
283
|
-
async getQueueLength(queue
|
|
283
|
+
async getQueueLength(queue) {
|
|
284
284
|
RabbitMq.validateName('queue', queue);
|
|
285
|
-
const { connection } = this.connectionsMap[connectionPurpose];
|
|
286
285
|
const { channel } = this;
|
|
287
286
|
if (!channel) {
|
|
288
287
|
throw new Error('channel is not defined');
|
|
289
288
|
}
|
|
290
|
-
debug('rabbit: getting queue length', { queue, connected: connection?.isConnected() });
|
|
289
|
+
debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
|
|
291
290
|
return channel?.checkQueue(queue);
|
|
292
291
|
}
|
|
293
|
-
async deleteQueue(queue
|
|
292
|
+
async deleteQueue(queue) {
|
|
294
293
|
RabbitMq.validateName('queue', queue);
|
|
295
|
-
const channel = await this.assertChannel(
|
|
294
|
+
const channel = await this.assertChannel();
|
|
296
295
|
logger_1.default.info('rabbit: deleting queue', { queue });
|
|
297
296
|
const deleteQueueRes = await channel.deleteQueue(queue);
|
|
298
297
|
debug('queue deleted', deleteQueueRes);
|
|
299
298
|
return deleteQueueRes;
|
|
300
299
|
}
|
|
301
|
-
async bindQueue(queue, exchange
|
|
302
|
-
const channel = await this.assertChannel(
|
|
300
|
+
async bindQueue(queue, exchange) {
|
|
301
|
+
const channel = await this.assertChannel();
|
|
303
302
|
await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
|
|
304
303
|
return channel.bindQueue(queue, exchange, '');
|
|
305
304
|
}
|
|
306
|
-
async setupQueue(queueName,
|
|
305
|
+
async setupQueue(queueName, options) {
|
|
307
306
|
let queue;
|
|
308
|
-
|
|
307
|
+
const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
|
|
308
|
+
const localeOptions = {
|
|
309
|
+
...options,
|
|
310
|
+
durable: true,
|
|
311
|
+
arguments: {
|
|
312
|
+
...options?.arguments,
|
|
313
|
+
'x-consumer-timeout': 1000 * 60 * 60 * 24,
|
|
314
|
+
'x-queue-type': shouldUseQuorum ? 'quorum' : 'classic',
|
|
315
|
+
},
|
|
316
|
+
};
|
|
309
317
|
try {
|
|
310
|
-
const channel = await this.assertChannel(
|
|
318
|
+
const channel = await this.assertChannel();
|
|
311
319
|
debug('assertQueue->channel.addSetup', { queueName });
|
|
312
|
-
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName,
|
|
320
|
+
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
313
321
|
debug('assertQueue->channel.assertQueue', { queueName });
|
|
314
|
-
queue = await channel.assertQueue(queueName,
|
|
322
|
+
queue = await channel.assertQueue(queueName, localeOptions);
|
|
315
323
|
}
|
|
316
324
|
catch (e) {
|
|
317
325
|
logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
|
|
318
326
|
if (!this.options?.dontRetryAssert) {
|
|
319
327
|
debug('retrying assertQueue', { queueName });
|
|
320
|
-
const channel = await this.assertChannel({ force: true
|
|
321
|
-
await this.deleteQueue(queueName
|
|
328
|
+
const channel = await this.assertChannel({ force: true });
|
|
329
|
+
await this.deleteQueue(queueName);
|
|
322
330
|
debug('retrying assertQueue->channel.addSetup', { queueName });
|
|
323
|
-
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName,
|
|
331
|
+
await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
|
|
324
332
|
debug('retrying assertQueue->channel.assertQueue', { queueName });
|
|
325
|
-
queue = await channel.assertQueue(queueName,
|
|
333
|
+
queue = await channel.assertQueue(queueName, localeOptions);
|
|
326
334
|
}
|
|
327
335
|
else {
|
|
328
336
|
throw e;
|
|
329
337
|
}
|
|
330
338
|
}
|
|
331
|
-
|
|
332
|
-
this.queues[queueName] = queueName;
|
|
339
|
+
this.queues[queueName] = queue;
|
|
333
340
|
return queue;
|
|
334
341
|
}
|
|
335
|
-
|
|
336
|
-
|
|
342
|
+
static shouldUseQuorum(queueName) {
|
|
343
|
+
const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
|
|
344
|
+
if (envQuorumQueuesWhitelist === '*') {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
if (envQuorumQueuesWhitelist) {
|
|
348
|
+
const whitelist = envQuorumQueuesWhitelist.split(',');
|
|
349
|
+
return whitelist.includes(queueName);
|
|
350
|
+
}
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
async assertQueue(queueName, options) {
|
|
337
354
|
RabbitMq.validateName('queue', queueName);
|
|
338
355
|
if (this.queues[queueName]) {
|
|
339
356
|
delete this.queueSetupPromises[queueName];
|
|
@@ -342,8 +359,7 @@ class RabbitMq {
|
|
|
342
359
|
if (this.queueSetupPromises[queueName]) {
|
|
343
360
|
return this.queueSetupPromises[queueName];
|
|
344
361
|
}
|
|
345
|
-
this.queueSetupPromises[queueName] = this.setupQueue(queueName,
|
|
346
|
-
debug('rabbit: done assert queue', { connectionPurpose, queueName });
|
|
362
|
+
this.queueSetupPromises[queueName] = this.setupQueue(queueName, options);
|
|
347
363
|
return this.queueSetupPromises[queueName];
|
|
348
364
|
}
|
|
349
365
|
saveConsumer(queue, callback, options) {
|
|
@@ -386,16 +402,17 @@ class RabbitMq {
|
|
|
386
402
|
}
|
|
387
403
|
logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
|
|
388
404
|
}
|
|
389
|
-
const channel = await this.getNewChannel({
|
|
405
|
+
const channel = await this.getNewChannel({});
|
|
390
406
|
return channel.addSetup(async (confirmChannel) => {
|
|
391
|
-
await
|
|
392
|
-
await confirmChannel.prefetch(limit,
|
|
407
|
+
const q = await this.assertQueue(queue, optionsWithDefaults);
|
|
408
|
+
await confirmChannel.prefetch(limit, false);
|
|
393
409
|
const { consumerTag } = await confirmChannel.consume(queue, async (msg) => {
|
|
394
410
|
if (!msg) {
|
|
395
411
|
return null;
|
|
396
412
|
}
|
|
397
413
|
const traceId = msg.properties.headers[consts_1.TRACING_HEADER];
|
|
398
414
|
const userId = msg.properties.headers[consts_1.USER_TRACING_HEADER];
|
|
415
|
+
const automationId = msg.properties.headers[consts_1.AUTOMATION_ID_HEADER];
|
|
399
416
|
const parsedMessage = RabbitMq.parseMsg(msg);
|
|
400
417
|
const releaseLock = await this.lockRedisIfNeeded(parsedMessage, optionsWithDefaults);
|
|
401
418
|
const trace = (0, zehut_1.newTrace)(zehut_1.traceTypes.RABBIT);
|
|
@@ -420,7 +437,10 @@ class RabbitMq {
|
|
|
420
437
|
outbreakTrace?.context.set(consts_1.TRACING_HEADER, traceId);
|
|
421
438
|
}
|
|
422
439
|
if (auditContext) {
|
|
423
|
-
await auditContext(queue
|
|
440
|
+
await auditContext(queue, {
|
|
441
|
+
userId,
|
|
442
|
+
automationId,
|
|
443
|
+
});
|
|
424
444
|
}
|
|
425
445
|
const shouldConsume = await this.shouldConsumeMessageByTimestamp(parsedMessage);
|
|
426
446
|
if (!shouldConsume) {
|
|
@@ -466,7 +486,7 @@ class RabbitMq {
|
|
|
466
486
|
RabbitMq.validateName('queue', queue);
|
|
467
487
|
const { limit, deadMessageTtl } = optionsWithDefaults;
|
|
468
488
|
await this.saveConsumer(queue, callback, options);
|
|
469
|
-
const channel = await this.getNewChannel({ name: `consume
|
|
489
|
+
const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
|
|
470
490
|
return channel.addSetup(async (c) => {
|
|
471
491
|
const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
|
|
472
492
|
await c.assertQueue(queue);
|
|
@@ -481,14 +501,14 @@ class RabbitMq {
|
|
|
481
501
|
async publish(exchange, content, customHeaders) {
|
|
482
502
|
return (0, utils_1.wrapSetImmediate)(async () => {
|
|
483
503
|
RabbitMq.validateName('exchange', exchange);
|
|
484
|
-
const channel = await this.assertChannel(
|
|
485
|
-
await this.assertExchange(exchange
|
|
504
|
+
const channel = await this.assertChannel();
|
|
505
|
+
await this.assertExchange(exchange);
|
|
486
506
|
await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
|
|
487
507
|
});
|
|
488
508
|
}
|
|
489
509
|
async sendToQueue(queue, content, options, customHeaders) {
|
|
490
510
|
try {
|
|
491
|
-
await this.assertChannel(
|
|
511
|
+
await this.assertChannel();
|
|
492
512
|
}
|
|
493
513
|
catch (e) {
|
|
494
514
|
logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
|
|
@@ -496,7 +516,7 @@ class RabbitMq {
|
|
|
496
516
|
}
|
|
497
517
|
try {
|
|
498
518
|
RabbitMq.validateName('queue', queue);
|
|
499
|
-
await this.assertQueue(queue,
|
|
519
|
+
await this.assertQueue(queue, options);
|
|
500
520
|
}
|
|
501
521
|
catch (e) {
|
|
502
522
|
logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
|
|
@@ -508,36 +528,31 @@ class RabbitMq {
|
|
|
508
528
|
return res;
|
|
509
529
|
}
|
|
510
530
|
catch (e) {
|
|
511
|
-
|
|
531
|
+
const isConnected = await this.isConnected();
|
|
532
|
+
logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
|
|
512
533
|
throw e;
|
|
513
534
|
}
|
|
514
535
|
}
|
|
515
536
|
async isConnected() {
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return false;
|
|
536
|
-
}
|
|
537
|
-
logger_1.default.info('rabbit: isConnected - true');
|
|
538
|
-
return true;
|
|
539
|
-
}));
|
|
540
|
-
return isEachConnectionConnected.every((isConnected) => isConnected === true);
|
|
537
|
+
const connection = await this.getConnection();
|
|
538
|
+
const isConnected = connection.isConnected();
|
|
539
|
+
if (!isConnected) {
|
|
540
|
+
logger_1.default.error('rabbit: isConnected - false');
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
const channel = await this.assertChannel();
|
|
544
|
+
try {
|
|
545
|
+
await Promise.all([
|
|
546
|
+
channel.waitForConnect(),
|
|
547
|
+
...this.consumers.map((c) => channel.checkQueue(c.queue)),
|
|
548
|
+
]);
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
logger_1.default.error('rabbit: isConnected - false');
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
logger_1.default.info('rabbit: isConnected - true');
|
|
555
|
+
return true;
|
|
541
556
|
}
|
|
542
557
|
async gracefulShutdown(signal) {
|
|
543
558
|
const tagsNumber = this.consumersTags.length;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface TaskData {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
interface SendTaskOptions {
|
|
5
|
+
taskName: string;
|
|
6
|
+
queueName: string;
|
|
7
|
+
}
|
|
8
|
+
declare function sendCeleryTaskViaHttp(data: TaskData, { taskName, queueName }: SendTaskOptions): Promise<void>;
|
|
9
|
+
export { sendCeleryTaskViaHttp, TaskData, SendTaskOptions };
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
exports.sendCeleryTaskViaHttp = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
// Environment configuration
|
|
10
|
+
const config = {
|
|
11
|
+
host: process.env.RABBITMQ_SERVICE_HOST || 'localhost',
|
|
12
|
+
username: process.env.RABBITMQ_USERNAME || 'guest',
|
|
13
|
+
password: process.env.RABBITMQ_PASSWORD || 'guest',
|
|
14
|
+
};
|
|
15
|
+
async function sendCeleryTaskViaHttp(data, { taskName, queueName }) {
|
|
16
|
+
const apiUrl = `http://${config.host}:15672/api/exchanges/%2f/amq.default/publish`;
|
|
17
|
+
const message = {
|
|
18
|
+
task: taskName,
|
|
19
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
20
|
+
args: [data],
|
|
21
|
+
};
|
|
22
|
+
const payload = {
|
|
23
|
+
properties: {
|
|
24
|
+
delivery_mode: 2,
|
|
25
|
+
content_type: 'application/json',
|
|
26
|
+
},
|
|
27
|
+
routing_key: queueName,
|
|
28
|
+
payload: JSON.stringify(message),
|
|
29
|
+
payload_encoding: 'string',
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch(apiUrl, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/json',
|
|
36
|
+
Authorization: `Basic ${Buffer.from(`${config.username}:${config.password}`).toString('base64')}`,
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(payload),
|
|
39
|
+
});
|
|
40
|
+
if (response.ok) {
|
|
41
|
+
const result = await response.json();
|
|
42
|
+
logger_1.default.info('Successfully published message:', result);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
logger_1.default.error(`Failed to publish message. Status code: ${response.status}`);
|
|
46
|
+
logger_1.default.error(`Response: ${await response.text()}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger_1.default.error('Error sending request:', error instanceof Error ? error.message : String(error));
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.sendCeleryTaskViaHttp = sendCeleryTaskViaHttp;
|
package/dist/lib/consts.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare const DEFAULT_LOCK_TIMEOUT: number;
|
|
|
3
3
|
export declare const RETRY_HEADER = "x-retry-count";
|
|
4
4
|
export declare const TRACING_HEADER = "x-trace-id";
|
|
5
5
|
export declare const USER_TRACING_HEADER = "x-af-user-id";
|
|
6
|
+
export declare const AUTOMATION_ID_HEADER = "x-af-automation-id";
|
|
6
7
|
export declare const USER_OBJECT = "userObject";
|
|
7
8
|
export declare const DEFAULT_USE_CONSUME_WITH_LOCK = false;
|
|
8
9
|
export declare const CONNECTION_CREATED_CONST = "connectionCreated";
|
package/dist/lib/consts.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_OPTIONS = exports.CONNECTION_FAILED_CONST = exports.CONNECTION_CREATED_CONST = exports.DEFAULT_USE_CONSUME_WITH_LOCK = exports.USER_OBJECT = exports.USER_TRACING_HEADER = exports.TRACING_HEADER = exports.RETRY_HEADER = exports.DEFAULT_LOCK_TIMEOUT = exports.DEFAULT_DEAD_TTL_TWO_DAYS = void 0;
|
|
3
|
+
exports.DEFAULT_OPTIONS = exports.CONNECTION_FAILED_CONST = exports.CONNECTION_CREATED_CONST = exports.DEFAULT_USE_CONSUME_WITH_LOCK = exports.USER_OBJECT = exports.AUTOMATION_ID_HEADER = exports.USER_TRACING_HEADER = exports.TRACING_HEADER = exports.RETRY_HEADER = exports.DEFAULT_LOCK_TIMEOUT = exports.DEFAULT_DEAD_TTL_TWO_DAYS = void 0;
|
|
4
4
|
exports.DEFAULT_DEAD_TTL_TWO_DAYS = 60000 * 60 * 12;
|
|
5
5
|
exports.DEFAULT_LOCK_TIMEOUT = 1000 * 5;
|
|
6
6
|
exports.RETRY_HEADER = 'x-retry-count';
|
|
7
7
|
exports.TRACING_HEADER = 'x-trace-id';
|
|
8
8
|
exports.USER_TRACING_HEADER = 'x-af-user-id';
|
|
9
|
+
exports.AUTOMATION_ID_HEADER = 'x-af-automation-id';
|
|
9
10
|
exports.USER_OBJECT = 'userObject';
|
|
10
11
|
exports.DEFAULT_USE_CONSUME_WITH_LOCK = false;
|
|
11
12
|
exports.CONNECTION_CREATED_CONST = 'connectionCreated';
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AmqpConnectionManager } from 'amqp-connection-manager';
|
|
2
1
|
import { ConsumeMessage, Options, Replies } from 'amqplib';
|
|
3
2
|
export interface ExchangesCache {
|
|
4
3
|
[key: string]: any;
|
|
@@ -9,6 +8,9 @@ export interface QueuesCache {
|
|
|
9
8
|
export interface QueueSetupPromisesDictionary {
|
|
10
9
|
[key: string]: Promise<Replies.AssertQueue> | undefined;
|
|
11
10
|
}
|
|
11
|
+
export interface AssertExchangePromisesDictionary {
|
|
12
|
+
[key: string]: Promise<Replies.AssertExchange> | undefined;
|
|
13
|
+
}
|
|
12
14
|
export type CustomMessageHeaders = {
|
|
13
15
|
redisTimestampValidationKey?: string;
|
|
14
16
|
};
|
|
@@ -39,11 +41,3 @@ export type AfConsumer = {
|
|
|
39
41
|
options: ConsumeOptions | undefined;
|
|
40
42
|
};
|
|
41
43
|
export declare const CONSUMER_DEFAULT_OPTIONS: Options.Consume;
|
|
42
|
-
export type ConnectionData = {
|
|
43
|
-
connection: AmqpConnectionManager | null;
|
|
44
|
-
creatingConnection: boolean;
|
|
45
|
-
};
|
|
46
|
-
export declare enum ConnectionPurpose {
|
|
47
|
-
Consume = "consume",
|
|
48
|
-
Publish = "publish"
|
|
49
|
-
}
|
package/dist/lib/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CONSUMER_DEFAULT_OPTIONS = void 0;
|
|
4
4
|
const HA_PROMOTE_ON_FAILURE = 'ha-promote-on-failure';
|
|
5
5
|
const HA_PROMOTE_ON_SHUTDOWN = 'ha-promote-on-shutdown';
|
|
6
6
|
exports.CONSUMER_DEFAULT_OPTIONS = {
|
|
@@ -9,8 +9,3 @@ exports.CONSUMER_DEFAULT_OPTIONS = {
|
|
|
9
9
|
[HA_PROMOTE_ON_SHUTDOWN]: 'always',
|
|
10
10
|
},
|
|
11
11
|
};
|
|
12
|
-
var ConnectionPurpose;
|
|
13
|
-
(function (ConnectionPurpose) {
|
|
14
|
-
ConnectionPurpose["Consume"] = "consume";
|
|
15
|
-
ConnectionPurpose["Publish"] = "publish";
|
|
16
|
-
})(ConnectionPurpose = exports.ConnectionPurpose || (exports.ConnectionPurpose = {}));
|
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,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/rabbit",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.23-beta.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=15.0.0"
|
|
8
|
+
},
|
|
6
9
|
"scripts": {
|
|
7
10
|
"postinstall": "echo '\\033[0;31m\nWARNING: in case of migrating to new version of @autofleet/rabbit \nyou might have to delete existing queues or the deployment will fail.\\033[0m\n'",
|
|
8
11
|
"start": "ts-node src/index.ts",
|
|
@@ -43,4 +46,4 @@
|
|
|
43
46
|
},
|
|
44
47
|
"author": "",
|
|
45
48
|
"license": "ISC"
|
|
46
|
-
}
|
|
49
|
+
}
|