@platform-x/hep-message-broker-client 1.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/README.md +1 -0
- package/dist/src/Util/commonUtil.d.ts +16 -0
- package/dist/src/Util/commonUtil.js +39 -0
- package/dist/src/Util/logger.d.ts +68 -0
- package/dist/src/Util/logger.js +195 -0
- package/dist/src/Util/requestTracer.d.ts +7 -0
- package/dist/src/Util/requestTracer.js +34 -0
- package/dist/src/config/ConfigManager.d.ts +9 -0
- package/dist/src/config/ConfigManager.js +67 -0
- package/dist/src/config/index.d.ts +29 -0
- package/dist/src/config/index.js +38 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +6 -0
- package/dist/src/messageBroker/BaseRabbitMQClient.d.ts +16 -0
- package/dist/src/messageBroker/BaseRabbitMQClient.js +29 -0
- package/dist/src/messageBroker/ConnectionManager.d.ts +60 -0
- package/dist/src/messageBroker/ConnectionManager.js +227 -0
- package/dist/src/messageBroker/MessageBrokerClient.d.ts +34 -0
- package/dist/src/messageBroker/MessageBrokerClient.js +102 -0
- package/dist/src/messageBroker/MessageConsumer.d.ts +26 -0
- package/dist/src/messageBroker/MessageConsumer.js +102 -0
- package/dist/src/messageBroker/MessageProducer.d.ts +29 -0
- package/dist/src/messageBroker/MessageProducer.js +130 -0
- package/dist/src/messageBroker/RabbitMQClient.d.ts +12 -0
- package/dist/src/messageBroker/RabbitMQClient.js +67 -0
- package/dist/src/messageBroker/RetryManager.d.ts +23 -0
- package/dist/src/messageBroker/RetryManager.js +72 -0
- package/dist/src/messageBroker/interface/ConnectionWrapper.d.ts +6 -0
- package/dist/src/messageBroker/interface/ConnectionWrapper.js +3 -0
- package/dist/src/messageBroker/interface/IMessageBrokerClient.d.ts +7 -0
- package/dist/src/messageBroker/interface/IMessageBrokerClient.js +3 -0
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.d.ts +114 -0
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +706 -0
- package/dist/src/messageBroker/types/ActionType.d.ts +1 -0
- package/dist/src/messageBroker/types/ActionType.js +3 -0
- package/dist/src/messageBroker/types/PublishMessageInputType.d.ts +7 -0
- package/dist/src/messageBroker/types/PublishMessageInputType.js +3 -0
- package/dist/src/models/MessageModel.d.ts +5 -0
- package/dist/src/models/MessageModel.js +15 -0
- package/dist/src/models/NotificationMessageModel.d.ts +0 -0
- package/dist/src/models/NotificationMessageModel.js +2 -0
- package/package.json +40 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
var _a;
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.MessageBrokerClient = void 0;
|
|
50
|
+
// Import the amqplib library for RabbitMQ
|
|
51
|
+
const amqp = __importStar(require("amqplib"));
|
|
52
|
+
const config_1 = __importDefault(require("../../config"));
|
|
53
|
+
const logger_1 = require("../../Util/logger");
|
|
54
|
+
const ConfigManager_1 = __importDefault(require("../../config/ConfigManager"));
|
|
55
|
+
// Remove lodash delay import
|
|
56
|
+
let configManager = ConfigManager_1.default.getInstance();
|
|
57
|
+
// Declare variables for the connection and channel
|
|
58
|
+
let connection;
|
|
59
|
+
let channel;
|
|
60
|
+
// Declare variable for check connection
|
|
61
|
+
let isConnectionOpen = false;
|
|
62
|
+
let configData = {};
|
|
63
|
+
const RABBITMQ = config_1.default === null || config_1.default === void 0 ? void 0 : config_1.default.RABBITMQ;
|
|
64
|
+
let maxRetries = RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.MAX_RETRIES;
|
|
65
|
+
let retry_delay = (_a = RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.TTL) === null || _a === void 0 ? void 0 : _a.split("|");
|
|
66
|
+
// let dlx_exchange:string = RABBITMQ.DLX_EXCHANGE;
|
|
67
|
+
let dlx_queue = RABBITMQ.DLX_QUEUE;
|
|
68
|
+
// let retry_exchange:string = RABBITMQ.RETRY_EXCHANGE;
|
|
69
|
+
// let retry_queue:string = RABBITMQ.RETRY_QUEUE;
|
|
70
|
+
let connectionRetry = 1;
|
|
71
|
+
let retryCountHeader = 'x-retry-count';
|
|
72
|
+
class MessageBrokerClient {
|
|
73
|
+
// private readonly correlationId: string;
|
|
74
|
+
// constructor() {
|
|
75
|
+
// this.correlationId = generateCorrelationId();
|
|
76
|
+
// }
|
|
77
|
+
/**
|
|
78
|
+
* Function to check the status of the connection
|
|
79
|
+
* @returns boolean
|
|
80
|
+
*/
|
|
81
|
+
isConnected() {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
return isConnectionOpen;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
;
|
|
87
|
+
/**
|
|
88
|
+
* Function to initialize the connection, channel and setup the queues and exchanges
|
|
89
|
+
* @param reqData
|
|
90
|
+
* @returns
|
|
91
|
+
*/
|
|
92
|
+
initialize() {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
logger_1.Logger.info('Reached to initialize', 'initialize');
|
|
95
|
+
configData = configManager.getConfig();
|
|
96
|
+
// dlx_exchange = configData?.dlx_exchange;
|
|
97
|
+
dlx_queue = configData === null || configData === void 0 ? void 0 : configData.dlx_queue;
|
|
98
|
+
// retry_exchange = configData?.retry_exchange;
|
|
99
|
+
// retry_queue = configData?.retry_queue;
|
|
100
|
+
let retries = 0;
|
|
101
|
+
// Retrie times connection
|
|
102
|
+
while (retries < maxRetries) {
|
|
103
|
+
try {
|
|
104
|
+
if (RABBITMQ.CONNECTION_ERROR === 'true' || RABBITMQ.CONNECTION_ERROR === true) {
|
|
105
|
+
throw new Error("Error in connection");
|
|
106
|
+
}
|
|
107
|
+
yield this.createConnection();
|
|
108
|
+
return { connection: connection, channel: channel };
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
retries++;
|
|
112
|
+
logger_1.Logger.error('initialize:Failed to connect to RabbitMQ', `Attempt ${retries} of ${maxRetries}.`);
|
|
113
|
+
if (retries >= maxRetries) {
|
|
114
|
+
logger_1.Logger.error('Max retries reached, cannot connect to RabbitMQ.', 'initialize');
|
|
115
|
+
return { connection, channel };
|
|
116
|
+
}
|
|
117
|
+
// Wait before retrying (e.g., 10 seconds)
|
|
118
|
+
yield new Promise(resolve => setTimeout(resolve, 10000));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
;
|
|
124
|
+
/**
|
|
125
|
+
* Function to publish a message with retry
|
|
126
|
+
* @param request
|
|
127
|
+
* @param classInstance
|
|
128
|
+
* @param messagePublisherErrorHandler
|
|
129
|
+
* @returns
|
|
130
|
+
*/
|
|
131
|
+
publishMessage(request
|
|
132
|
+
// , classInstance:any, messagePublisherErrorHandler:string
|
|
133
|
+
) {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
logger_1.Logger.info('Reached:publishMessage', 'publishMessage');
|
|
136
|
+
// Logger.debug('Reached:publishMessageToExchange', 'publishMessageToExchange',{classInstance, messagePublisherErrorHandler});
|
|
137
|
+
try {
|
|
138
|
+
if (isConnectionOpen) {
|
|
139
|
+
logger_1.Logger.info('Check connection open or not', 'publishMessage');
|
|
140
|
+
const queueName = request.queueName;
|
|
141
|
+
const data = request.message;
|
|
142
|
+
const messageBuffer = Buffer.from(JSON.stringify(data === null || data === void 0 ? void 0 : data.message));
|
|
143
|
+
// let attempt: number = 0;
|
|
144
|
+
// let retries: number = typeof data.message === 'object' && data.message !== null ? (data.message as { retries: number }).retries ?? 0 : 0;
|
|
145
|
+
// while (attempt < maxRetries ) {
|
|
146
|
+
logger_1.Logger.info('Max retries check', 'publishMessage');
|
|
147
|
+
const isSent = yield new Promise((resolve, reject) => {
|
|
148
|
+
let sent = channel.sendToQueue(queueName, Buffer.from(messageBuffer), {
|
|
149
|
+
persistent: true, // Ensures the message is persisted
|
|
150
|
+
// correlationId: this.correlationId,
|
|
151
|
+
});
|
|
152
|
+
if (sent) {
|
|
153
|
+
logger_1.Logger.debug(`Message sent successfully`, 'publishMessage', { data, queueName });
|
|
154
|
+
resolve(true);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
logger_1.Logger.error(`Failed to publish message.`, 'publishMessage', { message: messageBuffer.toString() });
|
|
158
|
+
reject(false);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
if ((isSent) && (RABBITMQ.PUBLISHER_ERROR !== 'true' && RABBITMQ.PUBLISHER_ERROR !== true)) {
|
|
162
|
+
return isSent;
|
|
163
|
+
}
|
|
164
|
+
// else{
|
|
165
|
+
// let queueName = (request as PublishMessageInputType)?.queueName
|
|
166
|
+
// if (attempt >= maxRetries) {
|
|
167
|
+
// Logger.error('Max retries reached. Failed to publish message.', 'publishMessage', request);
|
|
168
|
+
// // Optionally: Log or persist the failed message to a DB, file, or other storage for manual intervention
|
|
169
|
+
// this.sendMessageToDeadLatter(attempt, data, queueName);
|
|
170
|
+
// this.messagePublisherErrorHandler(request); // we need to comment this line
|
|
171
|
+
// if (typeof classInstance[messagePublisherErrorHandler] === 'function') {
|
|
172
|
+
// classInstance[messagePublisherErrorHandler](data); // Dynamically call the method
|
|
173
|
+
// } else {
|
|
174
|
+
// Logger.info(`Method ${messagePublisherErrorHandler} not found in classInstance.`, 'publishMessage');
|
|
175
|
+
// }
|
|
176
|
+
// return false;
|
|
177
|
+
// }else{
|
|
178
|
+
// await this.publishMessageRetryQueue(request, attempt);
|
|
179
|
+
// attempt++;
|
|
180
|
+
// }
|
|
181
|
+
// }
|
|
182
|
+
// }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
logger_1.Logger.error(`Error sending message: ${error}`, 'sendMessage');
|
|
187
|
+
throw new Error("Failed to publish message to queue");
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Function to publish a message with retry
|
|
193
|
+
* @param request
|
|
194
|
+
* @param classInstance
|
|
195
|
+
* @param messagePublisherErrorHandler
|
|
196
|
+
* @returns
|
|
197
|
+
*/
|
|
198
|
+
publishMessageToExchange(request) {
|
|
199
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
+
var _a;
|
|
201
|
+
logger_1.Logger.info('Reached:publishMessageToExchange', 'publishMessageToExchange');
|
|
202
|
+
// Publish the message
|
|
203
|
+
// Logger.debug('Reached:publishMessageToExchange', 'publishMessageToExchange',{classInstance, messagePublisherErrorHandler});
|
|
204
|
+
try {
|
|
205
|
+
if (isConnectionOpen) {
|
|
206
|
+
// let attempt: number = 0;
|
|
207
|
+
const exchangeName = (_a = request === null || request === void 0 ? void 0 : request.exchangeName) !== null && _a !== void 0 ? _a : '';
|
|
208
|
+
const queueName = request.queueName;
|
|
209
|
+
const data = request === null || request === void 0 ? void 0 : request.message;
|
|
210
|
+
// const options:object | null = request?.options; // Optional parameter for retry count if you wnats to override the default retry count
|
|
211
|
+
const messageBuffer = Buffer.from(JSON.stringify(data.message));
|
|
212
|
+
// let retries: number = typeof data.message === 'object' && data.message !== null ? (data.message as { retries: number }).retries ?? 0 : 0;
|
|
213
|
+
// while (attempt < maxRetries) {
|
|
214
|
+
const isSent = yield new Promise((resolve, reject) => {
|
|
215
|
+
const sent = channel.publish(exchangeName, queueName, messageBuffer, {
|
|
216
|
+
persistent: true, // Ensures the message is persisted
|
|
217
|
+
// correlationId: this.correlationId,
|
|
218
|
+
});
|
|
219
|
+
if (sent) {
|
|
220
|
+
logger_1.Logger.debug(`Message sent successfully`, 'publishMessageToExchange', { data, queueName });
|
|
221
|
+
resolve(true);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
logger_1.Logger.error(`Failed to publish message to exchange.`, 'publishMessageToExchange', { message: messageBuffer.toString() });
|
|
225
|
+
reject(false);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
if ((isSent) && (RABBITMQ.PUBLISHER_ERROR !== 'true' && RABBITMQ.PUBLISHER_ERROR !== true)) {
|
|
229
|
+
return isSent;
|
|
230
|
+
}
|
|
231
|
+
// else{
|
|
232
|
+
// let queueName = (request as PublishMessageInputType)?.queueName
|
|
233
|
+
// if (attempt >= maxRetries) {
|
|
234
|
+
// Logger.error('Max retries reached. Failed to publish message.', 'publishMessageToExchange', request);
|
|
235
|
+
// // Optionally: Log or persist the failed message to a DB, file, or other storage for manual intervention
|
|
236
|
+
// this.sendMessageToDeadLatter(attempt, data, queueName);
|
|
237
|
+
// this.messagePublisherErrorHandler(request); // we need to comment this line
|
|
238
|
+
// if (typeof classInstance[messagePublisherErrorHandler] === 'function') {
|
|
239
|
+
// classInstance[messagePublisherErrorHandler](data); // Dynamically call the method
|
|
240
|
+
// } else {
|
|
241
|
+
// Logger.info(`Method ${messagePublisherErrorHandler} not found in classInstance.`, 'publishMessageToExchange');
|
|
242
|
+
// }
|
|
243
|
+
// return false;
|
|
244
|
+
// }else{
|
|
245
|
+
// await this.publishMessageRetryQueue(request, (attempt+1));
|
|
246
|
+
// attempt++;
|
|
247
|
+
// }
|
|
248
|
+
// }
|
|
249
|
+
// }
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
logger_1.Logger.error(`Error sending message: ${error}`, 'sendMessage');
|
|
254
|
+
throw new Error("Failed to publish message to exchange");
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
;
|
|
259
|
+
/**
|
|
260
|
+
* Funciton to message handler
|
|
261
|
+
*/
|
|
262
|
+
// TO Do rename function name messagePublisherErrorHandler
|
|
263
|
+
messagePublisherErrorHandler(request) {
|
|
264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
logger_1.Logger.info(`${JSON.stringify(request)}`, 'messagePublisherErrorHandler');
|
|
266
|
+
return Promise.resolve(true);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Funvction for initialize consumer queue
|
|
271
|
+
* @param consumerQueues
|
|
272
|
+
*/
|
|
273
|
+
initializeConsumers(classInstance, consumerHandler, consumerErrorHandler) {
|
|
274
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
275
|
+
try {
|
|
276
|
+
logger_1.Logger.info('Reached in initialize consumer', `initializeConsumers`);
|
|
277
|
+
let consume_queues = configData === null || configData === void 0 ? void 0 : configData.consume_queues;
|
|
278
|
+
// Consume messages from all queues
|
|
279
|
+
for (let queueName in configData === null || configData === void 0 ? void 0 : configData.consume_queues) {
|
|
280
|
+
if (Object.prototype.hasOwnProperty.call(consume_queues, queueName)) {
|
|
281
|
+
// Call function Consume messages with retry
|
|
282
|
+
yield this.consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
logger_1.Logger.error('Error initializing consumers:', 'initializeConsumers', error.message);
|
|
288
|
+
throw new Error(error.message);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Function for perform action with retry
|
|
294
|
+
* @param actionHandler
|
|
295
|
+
* @param context
|
|
296
|
+
* @param failActionHandler
|
|
297
|
+
* @returns
|
|
298
|
+
*/
|
|
299
|
+
performActionWithRetry(actionHandler, failActionHandler, context) {
|
|
300
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
301
|
+
logger_1.Logger.info("Reached: in perform action with retry ", "performActionWithRetry");
|
|
302
|
+
let attempt = 0;
|
|
303
|
+
while (attempt < maxRetries) {
|
|
304
|
+
try {
|
|
305
|
+
actionHandler(context);
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
attempt++;
|
|
310
|
+
logger_1.Logger.error(`Failed to publish message. Attempt ${attempt} of ${maxRetries}. Error:`, 'performActionWithRetry', { message: error.message });
|
|
311
|
+
let queueName = context === null || context === void 0 ? void 0 : context.queueName;
|
|
312
|
+
const data = context === null || context === void 0 ? void 0 : context.message;
|
|
313
|
+
if (attempt >= maxRetries) {
|
|
314
|
+
logger_1.Logger.error('Max retries reached. Failed to publish message.', 'performActionWithRetry');
|
|
315
|
+
// Optionally: Log or persist the failed message to a DB, file, or other storage for manual intervention
|
|
316
|
+
this.sendMessageToDeadLatter(attempt, data);
|
|
317
|
+
failActionHandler(context);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
// Wait before retrying (Exponential Backoff)
|
|
321
|
+
let retryDelay;
|
|
322
|
+
retryDelay = Number(retry_delay[attempt - 1]);
|
|
323
|
+
let count = retry_delay.length - 1 === attempt ? retry_delay.length - 1 : retry_delay[attempt - 1];
|
|
324
|
+
retryDelay = Number(count);
|
|
325
|
+
this.sendMessageToRetryQueue(attempt, data, retryDelay, queueName);
|
|
326
|
+
logger_1.Logger.info(`Retrying in ${retryDelay / 1000} seconds...`, 'performActionWithRetry');
|
|
327
|
+
yield new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return false;
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Function to consume message with retry
|
|
335
|
+
* @param queueName
|
|
336
|
+
*/
|
|
337
|
+
consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler) {
|
|
338
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
logger_1.Logger.info("Reached: Consuming messages from the queue", 'consumeMessage');
|
|
340
|
+
let attempt = 0;
|
|
341
|
+
if (isConnectionOpen) {
|
|
342
|
+
return yield channel.consume(queueName, (message) => __awaiter(this, void 0, void 0, function* () {
|
|
343
|
+
var _a;
|
|
344
|
+
if (message) {
|
|
345
|
+
let msgData = JSON.parse(message.content.toString());
|
|
346
|
+
const headers = message.properties.headers || {};
|
|
347
|
+
attempt = headers[retryCountHeader] || 0;
|
|
348
|
+
const data = { body: (_a = msgData === null || msgData === void 0 ? void 0 : msgData.result) === null || _a === void 0 ? void 0 : _a.data, queue_name: queueName, language: msgData === null || msgData === void 0 ? void 0 : msgData.language, correlationId: msgData === null || msgData === void 0 ? void 0 : msgData.correlationId, retries: msgData === null || msgData === void 0 ? void 0 : msgData.retries, item_id: msgData === null || msgData === void 0 ? void 0 : msgData.item_id, metadatakey: msgData === null || msgData === void 0 ? void 0 : msgData.metadatakey };
|
|
349
|
+
try {
|
|
350
|
+
let success = false;
|
|
351
|
+
if (RABBITMQ.CONSUMER_ERROR !== 'true' && RABBITMQ.CONSUMER_ERROR !== true) {
|
|
352
|
+
logger_1.Logger.info("Consumer handler call for process the request", 'consumeMessage');
|
|
353
|
+
// success = await this.consumerHandler({ queueName, message: msgData });
|
|
354
|
+
if (typeof classInstance[consumerHandler] === 'function') {
|
|
355
|
+
success = yield classInstance[consumerHandler]({ queueName, message: msgData }); // Dynamically call the method
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
logger_1.Logger.info(`Method ${consumerHandler} not found in classInstance.`, 'consumerMessage');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!success) {
|
|
362
|
+
const retryCount = message.properties.headers['x-retry-count'] || 0;
|
|
363
|
+
// while (retryCount < maxRetries) {
|
|
364
|
+
attempt = retryCount ? retryCount : attempt;
|
|
365
|
+
if (retryCount >= maxRetries) {
|
|
366
|
+
logger_1.Logger.error('Max retries reached. Failed to publish message.', 'consumeMessage');
|
|
367
|
+
// Optionally: Log or persist the failed message to a DB, file, or other storage for manual intervention
|
|
368
|
+
this.sendMessageToDeadLatter(attempt, data);
|
|
369
|
+
// this.consumerErrorHandler(data);
|
|
370
|
+
if (typeof classInstance[consumerErrorHandler] === 'function') {
|
|
371
|
+
classInstance[consumerErrorHandler](data); // Dynamically call the method
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
logger_1.Logger.info(`Method ${consumerErrorHandler} not found in classInstance.`, 'consumerMessage');
|
|
375
|
+
}
|
|
376
|
+
channel.nack(message, false, false); // Move message to DLQ after failure
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
attempt++;
|
|
380
|
+
if ((data === null || data === void 0 ? void 0 : data.retries) >= 0) {
|
|
381
|
+
data.retries = attempt;
|
|
382
|
+
}
|
|
383
|
+
// Wait before retrying (Exponential Backoff)
|
|
384
|
+
let retryDelay;
|
|
385
|
+
let count = retry_delay.length === attempt ? retry_delay[retry_delay.length - 1] : retry_delay[attempt - 1];
|
|
386
|
+
retryDelay = Number(count);
|
|
387
|
+
yield this.sendMessageToRetryQueue(attempt, data, retryDelay, queueName);
|
|
388
|
+
logger_1.Logger.info(`Retrying in ${retryDelay / 1000} seconds...`, 'consumeMessage');
|
|
389
|
+
yield new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
logger_1.Logger.info(`Acknowledge the successful processing`, 'consumeMessage');
|
|
393
|
+
}
|
|
394
|
+
// Acknowledge the successful processing
|
|
395
|
+
channel.ack(message);
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
let errorMessage = error.message;
|
|
399
|
+
logger_1.Logger.error(`Error processing message`, 'consumeMessage', { message: errorMessage });
|
|
400
|
+
this.sendMessageToDeadLatter(attempt, data);
|
|
401
|
+
// this.consumerErrorHandler(data);
|
|
402
|
+
if (typeof classInstance[consumerErrorHandler] === 'function') {
|
|
403
|
+
classInstance[consumerErrorHandler](data); // Dynamically call the method
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
logger_1.Logger.info(`Method ${consumerErrorHandler} not found in classInstance.`, 'consumerMessage');
|
|
407
|
+
}
|
|
408
|
+
channel.nack(message, false, false); // Move message to DLQ after failure
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}));
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
;
|
|
416
|
+
// /**
|
|
417
|
+
// * Function for consumer massage handler
|
|
418
|
+
// * @param request
|
|
419
|
+
// * @returns
|
|
420
|
+
// */
|
|
421
|
+
// public async consumerHandler(request: PublishMessageInputType): Promise<boolean> {
|
|
422
|
+
// Logger.info(`${JSON.stringify(request)}`, 'consumerHandler');
|
|
423
|
+
// return true;
|
|
424
|
+
// }
|
|
425
|
+
// /**
|
|
426
|
+
// * Function to consumer message error handler
|
|
427
|
+
// * @param request
|
|
428
|
+
// * @returns
|
|
429
|
+
// */
|
|
430
|
+
// public async consumerErrorHandler(request:any):Promise<boolean> {
|
|
431
|
+
// Logger.info(`${JSON.stringify(request)}`, 'consumerErrorHandler');
|
|
432
|
+
// return true;
|
|
433
|
+
// }
|
|
434
|
+
/**
|
|
435
|
+
* Function to send message to dead later queue
|
|
436
|
+
* @param attempt
|
|
437
|
+
* @param data
|
|
438
|
+
* @param queueName
|
|
439
|
+
* @retruns
|
|
440
|
+
*/
|
|
441
|
+
sendMessageToDeadLatter(attempt, data) {
|
|
442
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
443
|
+
logger_1.Logger.info("Reached: send message on dead later queue", 'sendMessageToDeadLater');
|
|
444
|
+
try {
|
|
445
|
+
if (isConnectionOpen) {
|
|
446
|
+
return channel.sendToQueue(dlx_queue, Buffer.from(JSON.stringify(data)), {
|
|
447
|
+
persistent: true,
|
|
448
|
+
headers: {
|
|
449
|
+
'x-retry-count': attempt - 1
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
logger_1.Logger.error("Error in send message on dead later queue", 'sendMessageToDeadLater', { message: error.message });
|
|
456
|
+
throw error;
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
/***
|
|
461
|
+
* Function to send message to retry queue
|
|
462
|
+
* @param attempt
|
|
463
|
+
* @param data
|
|
464
|
+
* @param retryDelay
|
|
465
|
+
* @param queueName
|
|
466
|
+
* @returns
|
|
467
|
+
*/
|
|
468
|
+
sendMessageToRetryQueue(attempt, data, retryDelay, queueName) {
|
|
469
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
470
|
+
logger_1.Logger.info("Reached: send message on retry queue", 'sendMessageToRetryQueue');
|
|
471
|
+
try {
|
|
472
|
+
if (isConnectionOpen) {
|
|
473
|
+
const isSent = yield new Promise((resolve, reject) => {
|
|
474
|
+
const messageBuffer = Buffer.from(JSON.stringify(data));
|
|
475
|
+
let sent = channel.sendToQueue(queueName, messageBuffer, {
|
|
476
|
+
headers: {
|
|
477
|
+
'x-retry-count': attempt + 1,
|
|
478
|
+
'x-message-ttl': retryDelay,
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
if (sent) {
|
|
482
|
+
logger_1.Logger.debug(`Message sent successfully`, 'publishMessage', { data, queueName });
|
|
483
|
+
resolve(true);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
logger_1.Logger.error(`Failed to publish message.`, 'publishMessage', { message: data.toString() });
|
|
487
|
+
reject(false);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
return isSent;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
logger_1.Logger.error("Error in send message on retry queue", 'sendMessageToRetryQueue', { message: error.message });
|
|
495
|
+
throw error;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Function to find the queue, exchange and add binding
|
|
501
|
+
* @param queueName
|
|
502
|
+
* @param exchangeName
|
|
503
|
+
* @returns
|
|
504
|
+
*/
|
|
505
|
+
findQueueAndExchange(queueName, exchangeName) {
|
|
506
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
507
|
+
var _a;
|
|
508
|
+
logger_1.Logger.info('Reached to findQueueAndExchange', 'findQueueAndExchange');
|
|
509
|
+
try {
|
|
510
|
+
let exchanges = configData === null || configData === void 0 ? void 0 : configData.exchanges;
|
|
511
|
+
let queues = configData.queues;
|
|
512
|
+
let bindings = configData.bindings;
|
|
513
|
+
// Declare the queues with dlx
|
|
514
|
+
for (let data of queues) {
|
|
515
|
+
if ((data === null || data === void 0 ? void 0 : data.name) === queueName) {
|
|
516
|
+
yield this.createQueue(data);
|
|
517
|
+
}
|
|
518
|
+
logger_1.Logger.info(`${data === null || data === void 0 ? void 0 : data.name} queue created `, 'findQueueAndExchange');
|
|
519
|
+
}
|
|
520
|
+
// Declare the exchange with dlx
|
|
521
|
+
for (let data of exchanges) {
|
|
522
|
+
if ((data === null || data === void 0 ? void 0 : data.name) === exchangeName) {
|
|
523
|
+
yield this.createExchange(data);
|
|
524
|
+
}
|
|
525
|
+
logger_1.Logger.info(`${data === null || data === void 0 ? void 0 : data.name} exchange created`, 'findQueueAndExchange');
|
|
526
|
+
}
|
|
527
|
+
// Declare the bindings for queues and exchanges with routing keys
|
|
528
|
+
for (let obj in bindings) {
|
|
529
|
+
(_a = bindings[obj]) === null || _a === void 0 ? void 0 : _a.forEach((key) => __awaiter(this, void 0, void 0, function* () {
|
|
530
|
+
if (obj === exchangeName && (key === null || key === void 0 ? void 0 : key.queue) === queueName) {
|
|
531
|
+
yield this.bindQueueAndExchanges(obj, key === null || key === void 0 ? void 0 : key.queue, key === null || key === void 0 ? void 0 : key.routingKey);
|
|
532
|
+
}
|
|
533
|
+
logger_1.Logger.info(`${key === null || key === void 0 ? void 0 : key.queue} bind with exchange name ${obj} and routing key ${key === null || key === void 0 ? void 0 : key.routingKey}`, 'findQueueAndExchange');
|
|
534
|
+
}));
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
catch (error) {
|
|
538
|
+
logger_1.Logger.error("Error on setup queues, exchanges and binding", 'findQueueAndExchange', error.message);
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Function to setup the queues and exchanges
|
|
545
|
+
* @params array
|
|
546
|
+
* @rtrun
|
|
547
|
+
*/
|
|
548
|
+
setupQueuesAndExchanges() {
|
|
549
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
550
|
+
var _a;
|
|
551
|
+
logger_1.Logger.info('Reached to setupQueuesAndExchanges', 'setupQueuesAndExchanges');
|
|
552
|
+
try {
|
|
553
|
+
let exchanges = configData.exchanges;
|
|
554
|
+
let queues = configData.queues;
|
|
555
|
+
let bindings = configData.bindings;
|
|
556
|
+
// Declare the exchange with dlx
|
|
557
|
+
for (let data of exchanges) {
|
|
558
|
+
yield this.createExchange(data);
|
|
559
|
+
logger_1.Logger.info(`${data === null || data === void 0 ? void 0 : data.name} exchange created`, 'setupQueuesAndExchanges');
|
|
560
|
+
}
|
|
561
|
+
// Declare the queues with dlx
|
|
562
|
+
for (let data of queues) {
|
|
563
|
+
yield this.createQueue(data);
|
|
564
|
+
logger_1.Logger.info(`${data === null || data === void 0 ? void 0 : data.name} queue created `, 'setupQueuesAndExchanges');
|
|
565
|
+
}
|
|
566
|
+
// Declare the bindings for queues and exchanges with routing keys
|
|
567
|
+
for (let obj in bindings) {
|
|
568
|
+
(_a = bindings[obj]) === null || _a === void 0 ? void 0 : _a.forEach((key) => __awaiter(this, void 0, void 0, function* () {
|
|
569
|
+
yield this.bindQueueAndExchanges(obj, key === null || key === void 0 ? void 0 : key.queue, key === null || key === void 0 ? void 0 : key.routingKey);
|
|
570
|
+
logger_1.Logger.info(`${key === null || key === void 0 ? void 0 : key.queue} bind with exchange name ${obj} and routing key ${key === null || key === void 0 ? void 0 : key.routingKey}`, 'setupQueuesAndExchanges');
|
|
571
|
+
}));
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
logger_1.Logger.error("Error on setup queues, exchanges and binding", 'setupQueuesAndExchanges', error.message);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
;
|
|
580
|
+
/**
|
|
581
|
+
* Function to binding queue and exchange
|
|
582
|
+
* @param exchangeName
|
|
583
|
+
* @param queueName
|
|
584
|
+
* @param routingKey
|
|
585
|
+
*/
|
|
586
|
+
bindQueueAndExchanges(exchangeName, queueName, routingKey) {
|
|
587
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
588
|
+
try {
|
|
589
|
+
yield channel.bindQueue(queueName, exchangeName, routingKey, { 'toQueue': queueName, 'x-match': 'any' });
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
logger_1.Logger.error('Error in bind Queue and exchange', 'bindQueueAndExchanges', { message: error.message });
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Function to create the queue
|
|
598
|
+
* @param data
|
|
599
|
+
*/
|
|
600
|
+
createQueue(data) {
|
|
601
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
602
|
+
try {
|
|
603
|
+
yield channel.assertQueue(data === null || data === void 0 ? void 0 : data.name, { durable: data.durable, exclusive: data.exclusive, autoDelete: data.autoDelete, arguments: data.arguments });
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
logger_1.Logger.error('Error in Create Queue', 'createQueue', { message: error.message });
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Function to create the exchange
|
|
612
|
+
* @param data
|
|
613
|
+
*/
|
|
614
|
+
createExchange(data) {
|
|
615
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
616
|
+
try {
|
|
617
|
+
yield channel.assertExchange(data === null || data === void 0 ? void 0 : data.name, data.type, { durable: data.durable, autoDelete: data.autoDelete });
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
logger_1.Logger.error('Error in Create exchange', 'createExchange', { message: error.message });
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
// private async publishMessageRetryQueue(request: PublishMessageInputType, attempt: number) {
|
|
625
|
+
// try {
|
|
626
|
+
// Logger.error(`Failed to publish message. Attempt ${attempt} of ${maxRetries}. Error:`, 'publishMessageRetryQueue', request);
|
|
627
|
+
// let queueName = (request as PublishMessageInputType)?.queueName
|
|
628
|
+
// const data: MessageModel = (request as PublishMessageInputType)?.message;
|
|
629
|
+
// if (typeof data.message === 'object' && data.message !== null) {
|
|
630
|
+
// (data.message as { retries: number }).retries = attempt;
|
|
631
|
+
// }
|
|
632
|
+
// // Wait before retrying (Exponential Backoff)
|
|
633
|
+
// let retryDelay: number;
|
|
634
|
+
// retryDelay = Number(retry_delay[attempt]);
|
|
635
|
+
// let count:any = retry_delay.length - 1 === attempt?retry_delay[retry_delay.length - 1]:retry_delay[attempt];
|
|
636
|
+
// retryDelay = Number(count);
|
|
637
|
+
// await this.sendMessageToRetryQueue(attempt, data, retryDelay, queueName);
|
|
638
|
+
// Logger.info(`Retrying in ${retryDelay / 1000}, seconds...`, 'publishMessageRetryQueue');
|
|
639
|
+
// await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
640
|
+
// } catch (error) {
|
|
641
|
+
// Logger.error(`Failed to publish message. Attempt ${attempt} of ${maxRetries}. Error:`, 'publishMessageRetryQueue', request);
|
|
642
|
+
// throw error;
|
|
643
|
+
// }
|
|
644
|
+
// }
|
|
645
|
+
/**
|
|
646
|
+
* Function to connect create to RabbitMQ
|
|
647
|
+
*/
|
|
648
|
+
createConnection() {
|
|
649
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
650
|
+
try {
|
|
651
|
+
logger_1.Logger.info('Reached to createConnection', 'createConnection');
|
|
652
|
+
configManager.loadConfig(RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.CONFIG_PATH);
|
|
653
|
+
let url = `amqp://${RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.USER}:${RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.PASS}@${RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.HOST}`;
|
|
654
|
+
// Create a connection to RabbitMQ server
|
|
655
|
+
connection = yield amqp.connect(url, { heartbeat: RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.HEARTBEAT });
|
|
656
|
+
isConnectionOpen = true;
|
|
657
|
+
// check the connection status
|
|
658
|
+
this.bindConnectionEventHandler();
|
|
659
|
+
// create channel
|
|
660
|
+
channel = yield connection.createConfirmChannel();
|
|
661
|
+
channel.prefetch(RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.PREFETCH_COUNT);
|
|
662
|
+
logger_1.Logger.info('RabbitMQ connected successfully! ', 'createConnection');
|
|
663
|
+
// create exchange and queue and bind with exchange
|
|
664
|
+
yield this.setupQueuesAndExchanges();
|
|
665
|
+
const connectionWrapper = { connection, channel };
|
|
666
|
+
return connectionWrapper;
|
|
667
|
+
}
|
|
668
|
+
catch (error) {
|
|
669
|
+
// Log and rethrow any errors that occur during connection
|
|
670
|
+
logger_1.Logger.error('Failed to connect to RabbitMQ', 'connection', error === null || error === void 0 ? void 0 : error.message);
|
|
671
|
+
return { connection: null, channel: null };
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Function for bind connection event handler on close and error setupQueuesAndExchanges
|
|
677
|
+
* @returns
|
|
678
|
+
*/
|
|
679
|
+
bindConnectionEventHandler() {
|
|
680
|
+
try {
|
|
681
|
+
connection.on('close', (err) => __awaiter(this, void 0, void 0, function* () {
|
|
682
|
+
logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, err);
|
|
683
|
+
isConnectionOpen = false;
|
|
684
|
+
if (connectionRetry <= maxRetries) {
|
|
685
|
+
yield this.createConnection();
|
|
686
|
+
connectionRetry++;
|
|
687
|
+
}
|
|
688
|
+
}));
|
|
689
|
+
connection.on('error', (err) => __awaiter(this, void 0, void 0, function* () {
|
|
690
|
+
logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:error`, `Connection error`, err);
|
|
691
|
+
isConnectionOpen = false;
|
|
692
|
+
if (connectionRetry <= maxRetries) {
|
|
693
|
+
yield this.createConnection();
|
|
694
|
+
connectionRetry++;
|
|
695
|
+
}
|
|
696
|
+
}));
|
|
697
|
+
return isConnectionOpen;
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
isConnectionOpen = false;
|
|
701
|
+
return isConnectionOpen;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
exports.MessageBrokerClient = MessageBrokerClient;
|
|
706
|
+
//# sourceMappingURL=MessageBrokerClient.js.map
|