@platform-x/hep-message-broker-client 1.1.16 → 1.1.17

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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/dist/src/messageBroker/rabbitmq/MessageBroker.js +25 -27
  3. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +31 -33
  4. package/package.json +43 -43
  5. package/rabbitMQConfig.json +344 -0
  6. package/dist/src/Util/commonUtil.js.map +0 -1
  7. package/dist/src/Util/constants.js.map +0 -1
  8. package/dist/src/Util/logger.js.map +0 -1
  9. package/dist/src/Util/requestTracer.js.map +0 -1
  10. package/dist/src/config/ConfigManager.js.map +0 -1
  11. package/dist/src/config/index.js.map +0 -1
  12. package/dist/src/index.js.map +0 -1
  13. package/dist/src/messageBroker/BaseRabbitMQClient.js.map +0 -1
  14. package/dist/src/messageBroker/ConnectionManager.js.map +0 -1
  15. package/dist/src/messageBroker/MessageBrokerClient.js.map +0 -1
  16. package/dist/src/messageBroker/MessageConsumer.js.map +0 -1
  17. package/dist/src/messageBroker/MessageProducer.js.map +0 -1
  18. package/dist/src/messageBroker/RabbitMQClient.js.map +0 -1
  19. package/dist/src/messageBroker/RetryManager.js.map +0 -1
  20. package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +0 -1
  21. package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +0 -1
  22. package/dist/src/messageBroker/rabbitmq/MessageBroker.js.map +0 -1
  23. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +0 -1
  24. package/dist/src/messageBroker/types/ActionType.js.map +0 -1
  25. package/dist/src/messageBroker/types/PublishMessageInputType.js.map +0 -1
  26. package/dist/src/models/MessageModel.js.map +0 -1
  27. package/dist/src/models/NotificationMessageModel.js.map +0 -1
  28. package/src/Util/commonUtil.ts +0 -41
  29. package/src/Util/constants.ts +0 -9
  30. package/src/Util/logger.ts +0 -219
  31. package/src/Util/requestTracer.ts +0 -28
  32. package/src/config/ConfigManager.ts +0 -35
  33. package/src/config/index.ts +0 -38
  34. package/src/index.ts +0 -74
  35. package/src/messageBroker/BaseRabbitMQClient.ts +0 -30
  36. package/src/messageBroker/ConnectionManager.ts +0 -182
  37. package/src/messageBroker/MessageBrokerClient.ts +0 -88
  38. package/src/messageBroker/MessageConsumer.ts +0 -85
  39. package/src/messageBroker/MessageProducer.ts +0 -142
  40. package/src/messageBroker/RabbitMQClient.ts +0 -47
  41. package/src/messageBroker/RetryManager.ts +0 -64
  42. package/src/messageBroker/interface/ConnectionWrapper.ts +0 -7
  43. package/src/messageBroker/interface/IMessageBrokerClient.ts +0 -11
  44. package/src/messageBroker/rabbitmq/MessageBroker.ts +0 -525
  45. package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +0 -681
  46. package/src/messageBroker/types/ActionType.ts +0 -1
  47. package/src/messageBroker/types/PublishMessageInputType.ts +0 -8
  48. package/src/models/MessageModel.ts +0 -14
  49. package/src/models/NotificationMessageModel.ts +0 -0
  50. package/tsconfig.json +0 -73
@@ -1,525 +0,0 @@
1
- import * as amqp from 'amqplib';
2
- import config from '../../config';
3
- import ConfigManager from '../../config/ConfigManager';
4
- import { Logger } from '../../Util/logger';
5
- import { RABBITMQ_FEED_TYPE, SECRET_KEYS } from '../../Util/constants';
6
- import { getIAMSecrets } from '../..';
7
-
8
- const { RABBITMQ } = config;
9
-
10
- let configManager: ConfigManager = ConfigManager.getInstance();
11
- let maxRetries = RABBITMQ.MAX_RETRIES;
12
- let retryDelay: any = RABBITMQ?.TTL?.split("|");
13
- let prefetchCount = RABBITMQ.PREFETCH_COUNT;
14
- let configData: any = {};
15
-
16
- export class MessageBroker {
17
-
18
- private connection: amqp.Connection | null = null;
19
- private channel: amqp.Channel | null = null;
20
-
21
- /**
22
- * Description: Checks if the RabbitMQ connection and channel are established.
23
- * @returns boolean indicating the connection status
24
- */
25
- public isConnected(): boolean {
26
- return this.connection !== null && this.channel !== null;
27
- }
28
-
29
- /**
30
- * Description: Checks if the connection and channel are alive. If not, recreates them.
31
- * Also recreates the channel if its underlying socket/stream is destroyed.
32
- */
33
- public async checkConnectionAndChannel(): Promise<void> {
34
- Logger.info('Reached: checkConnectionAndChannel', 'checkConnectionAndChannel');
35
- if (!this.isConnected()) {
36
- Logger.warn('No active connection found. Recreating connection...', 'checkConnectionAndChannel');
37
- await this.createConnection();
38
- return;
39
- }
40
- // Check if the channel's underlying stream is still alive
41
- const channelConn: any = (this.channel as any)?.connection;
42
- if (!this.channel || !channelConn || channelConn.stream?.destroyed) {
43
- Logger.warn('Channel is dead. Recreating channel...', 'checkConnectionAndChannel');
44
- await this.recreateChannel();
45
- }
46
- }
47
-
48
- /**
49
- * Description: Recreates the channel on the existing connection.
50
- */
51
- private async recreateChannel(): Promise<void> {
52
- try {
53
- this.channel = await this.connection!.createConfirmChannel();
54
- await this.channel.prefetch(prefetchCount);
55
- Logger.info('Channel recreated successfully', 'recreateChannel');
56
- } catch (error) {
57
- Logger.error(`Failed to recreate channel: ${(error as Error).message}`, 'recreateChannel');
58
- throw error;
59
- }
60
- }
61
-
62
- /**
63
- * Initialize RabbitMQ connection and channel with configurable retry attempts.
64
- * Waits for a configurable delay between each retry.
65
- */
66
- public async initialize(): Promise<{ connection: amqp.Connection; channel: amqp.Channel }> {
67
- try {
68
- configData = configManager.getConfig();
69
- Logger.info('Reached to createConnection', 'createConnection');
70
- let attempt = 0;
71
- while (attempt < maxRetries) {
72
- try {
73
- if(RABBITMQ.CONNECTION_RETRY_ERROR === 'true' || RABBITMQ.CONNECTION_RETRY_ERROR === true){
74
- throw new Error("Error in connection");
75
- }
76
- return await this.createConnection();
77
- } catch (error) {
78
- attempt++;
79
- Logger.error(`Attempt ${attempt} - Failed to connect to RabbitMQ: ${(error as Error).message}`, 'initialize');
80
- if (attempt < maxRetries - 1) {
81
- Logger.info(`Retrying to connect to RabbitMQ in ${retryDelay / 1000} seconds...`, 'initialize');
82
- await new Promise(res => setTimeout(res, retryDelay));
83
- }
84
- }
85
- }
86
- throw new Error(`Failed to connect to RabbitMQ after ${maxRetries} attempts`);
87
- } catch (error: any) {
88
- Logger.error("Connection to RabbitMQ failed.", 'createConnection');
89
- Logger.error(`Failed to connect to RabbitMQ: ${(error as Error).message}`, 'createConnection');
90
- throw error; // Rethrow the error after logging
91
- }
92
- }
93
-
94
- /**
95
- * Description: Establishes a connection to RabbitMQ and creates a channel. Also registers exchanges, queues, and bindings based on the configuration data.
96
- * @returns An object containing the RabbitMQ connection and channel.
97
- */
98
- public async createConnection():Promise<{ connection: amqp.Connection; channel: amqp.Channel }>{
99
- try {
100
- Logger.info('Attempting to connect to RabbitMQ', 'createConnection');
101
- configManager.loadConfig(RABBITMQ?.CONFIG_PATH);
102
- const secret = await getIAMSecrets();
103
- let url: string = `amqp://${secret?.[SECRET_KEYS.RABBITMQ_USER]}:${secret?.[SECRET_KEYS.RABBITMQ_PASS]}@${RABBITMQ?.HOST}`;
104
- // console.log(SECRET_KEYS.RABBITMQ_USER, SECRET_KEYS.RABBITMQ_PASS);
105
- // const url = `amqp://${RABBITMQ.USER}:${RABBITMQ.PASS}@${RABBITMQ.HOST}:${RABBITMQ.PORT}`;
106
-
107
- this.connection = await amqp.connect(url, { heartbeat: RABBITMQ.HEARTBEAT });
108
- this.channel = await this.connection.createConfirmChannel();
109
-
110
- this.connectionEventHandler(); // Event handlers for connection 'error' and 'close'
111
-
112
- await this.channel.prefetch(prefetchCount);
113
- await this.registerQueueAndExchange();
114
-
115
- Logger.info(`Connected to RabbitMQ`, 'createConnection');
116
- return { connection: this.connection, channel: this.channel };
117
- } catch (error) {
118
- Logger.error(`Failed to connect to RabbitMQ: ${(error as Error).message}`, 'createConnection');
119
- throw error;
120
- }
121
- }
122
-
123
- /**
124
- * Description: Registers 'close' and 'error' event handlers on the current connection.
125
- * - 'error' only logs (amqplib always fires 'close' after 'error', so reconnect is handled there).
126
- * - 'close' nullifies connection/channel, then attempts reconnect with exponential backoff.
127
- * - connectionRetry resets on each successful connection via createConnection().
128
- */
129
- private connectionEventHandler(): void {
130
- try {
131
- if (!this.connection) return;
132
- this.connection.on('error', (err: Error) => {
133
- Logger.error(`RabbitMQ connection error: ${err.message}`, 'connectionEventHandler');
134
- });
135
- this.connection.on('close', async () => {
136
- Logger.warn('RabbitMQ connection closed', 'connectionEventHandler');
137
- this.connection = null;
138
- this.channel = null;
139
- await this.handleReconnect();
140
- });
141
- } catch(error) {
142
- Logger.error(`Error in connectionEventHandler: ${(error as Error).message}`, 'connectionEventHandler');
143
- }
144
- }
145
-
146
- /**
147
- * Description: Attempts to reconnect to RabbitMQ with exponential backoff.
148
- * Resets connectionRetry on success so future disconnections can recover.
149
- */
150
- private async handleReconnect(): Promise<void> {
151
- let connectionRetry:number = 1;
152
- const retryDelays = RABBITMQ.TTL.split('|').map(Number);
153
-
154
- while (connectionRetry <= maxRetries) {
155
- const delay = retryDelays[connectionRetry - 1] ?? retryDelays[retryDelays.length - 1];
156
- Logger.info(`Reconnect attempt ${connectionRetry} of ${maxRetries} in ${delay / 1000}s...`, 'handleReconnect');
157
- await new Promise(res => setTimeout(res, delay));
158
-
159
- try {
160
- await this.createConnection();
161
- connectionRetry = 1;
162
- Logger.info('Reconnected to RabbitMQ successfully', 'handleReconnect');
163
- return;
164
- } catch (error) {
165
- Logger.error(`Reconnect attempt ${connectionRetry} failed: ${(error as Error).message}`, 'handleReconnect');
166
- connectionRetry++;
167
- }
168
- }
169
- Logger.error('Max reconnection attempts reached. No longer trying to reconnect.', 'handleReconnect');
170
- }
171
-
172
- /**
173
- * Description: Registers exchanges, queues, and bindings in RabbitMQ based on the provided configuration data.
174
- */
175
- public async registerQueueAndExchange(){
176
- Logger.info('Reached to registerQueueAndExchange', 'registerQueueAndExchange');
177
- try {
178
- const { exchanges = [], queues = [], bindings = {} } = configData;
179
-
180
- // Create all exchanges
181
- for (const exchange of exchanges) {
182
- await this.createExchange(exchange);
183
- Logger.info(`${exchange.name} exchange registered`, 'registerQueueAndExchange');
184
- }
185
-
186
- // Create all queues
187
- for (const queue of queues) {
188
- await this.createQueue(queue);
189
- Logger.info(`${queue.name} queue registered`, 'registerQueueAndExchange');
190
- }
191
-
192
- // Bind all queues to exchanges with routing keys
193
- for (const exchangeName in bindings) {
194
- for (const binding of bindings[exchangeName]) {
195
- await this.bindQueueAndExchanges(exchangeName, binding.queue, binding.routingKey, binding.options);
196
- Logger.info(`${binding.queue} bound to exchange ${exchangeName} with routing key ${binding.routingKey}`, 'registerQueueAndExchange');
197
- }
198
- }
199
- } catch (error) {
200
- Logger.error("Error on registering queue, exchange and binding", 'registerQueueAndExchange', (error as Error).message);
201
- throw error;
202
- }
203
- }
204
-
205
-
206
- /**
207
- * Description: Binds a RabbitMQ queue to an exchange with a specified routing key.
208
- * @param exchangeName
209
- * @param queueName
210
- * @param routingKey
211
- */
212
- private async bindQueueAndExchanges(exchangeName: string, queueName: string, routingKey: string, options: any) {
213
- Logger.info('Reached to bindQueueAndExchanges', 'bindQueueAndExchanges');
214
- try {
215
- if(options) {
216
- await this.channel!.bindQueue(queueName, exchangeName, routingKey, options);
217
- Logger.info(`Queue ${queueName} bound to exchange ${exchangeName} with routing key ${routingKey} and options ${JSON.stringify(options)}`, 'bindQueueAndExchanges');
218
- return;
219
- }
220
- await this.channel!.bindQueue(queueName, exchangeName, routingKey);
221
- Logger.info(`Queue ${queueName} bound to exchange ${exchangeName} with routing key ${routingKey}`, 'bindQueueAndExchanges');
222
- } catch (error) {
223
- Logger.error(`Failed to bind queue ${queueName} to exchange ${exchangeName}: ${(error as Error).message}`, 'bindQueueAndExchanges');
224
- throw error;
225
- }
226
- }
227
-
228
- /**
229
- * Description: Creates a RabbitMQ exchange with the specified configuration.
230
- * @param exchangeData
231
- */
232
- private async createExchange(exchangeData: any) {
233
- Logger.info('Reached to createExchange', 'createExchange');
234
- try {
235
- await this.channel!.assertExchange(exchangeData?.name, exchangeData?.type, { durable: exchangeData?.durable, autoDelete: exchangeData?.autoDelete, arguments: exchangeData?.arguments });
236
- Logger.info(`${exchangeData?.name} exchange created`, 'createExchange');
237
- } catch (error) {
238
- Logger.error(`Failed to create ${exchangeData?.name} exchange: ${(error as Error).message}`, 'createExchange');
239
- throw error;
240
- }
241
- }
242
-
243
- /**
244
- * Description: Creates a RabbitMQ queue with the specified configuration.
245
- * @param queueData
246
- */
247
- private async createQueue(queueData: any) {
248
- Logger.info('Reached to createQueue', 'createQueue');
249
- try {
250
- await this.channel!.assertQueue(queueData?.name, { durable: queueData?.durable, exclusive: queueData?.exclusive, autoDelete: queueData?.autoDelete, arguments: queueData?.arguments });
251
- Logger.info(`${queueData?.name} queue created`, 'createQueue');
252
- } catch (error) {
253
- Logger.error(`Failed to create ${queueData?.name} queue: ${(error as Error).message}`, 'createQueue');
254
- throw error;
255
- }
256
- }
257
-
258
- /**
259
- * Description: Publishes a message to a RabbitMQ exchange with configurable retry attempts.
260
- * On each failed attempt, waits using exponential backoff based on TTL config.
261
- * After all retries are exhausted, sends the message to the dead letter queue.
262
- * @param exchangeName - The target exchange name
263
- * @param queueName - The routing key / queue name
264
- * @param message - The message payload to publish
265
- * @returns true if published successfully
266
- */
267
- public async publishMessageToExchange(request: { exchangeName: string; queueName: string; message: any }): Promise<boolean> {
268
- Logger.info('Reached to publishMessageToExchange', 'publishMessageToExchange');
269
- const { exchangeName, queueName, message } = request;
270
- const retryDelayConfig = message?.message?.feed_type === RABBITMQ_FEED_TYPE.OVR ? RABBITMQ.OVR_TTL : RABBITMQ.ETX_TTL;
271
- const retryDelay = retryDelayConfig.split('|').map(Number);
272
-
273
- let attempt = 0;
274
- while (attempt < maxRetries) {
275
- try {
276
- await this.checkConnectionAndChannel();
277
- const messageBuffer = Buffer.from(JSON.stringify(message));
278
- const sent = this.channel!.publish(exchangeName, queueName, messageBuffer, { persistent: true });
279
- //if(attempt < 1){ sent = false}else{sent = true} // --- IGNORE ---
280
- if (sent && (RABBITMQ.PUBLISHER_RETRY_ERROR !== 'true' && RABBITMQ.PUBLISHER_RETRY_ERROR !== true)) {
281
- Logger.info(`Message published successfully on attempt ${attempt + 1}`, 'publishMessageToExchange');
282
- return true;
283
- } else {
284
- throw new Error('Channel publish returned false — buffer full');
285
- }
286
- } catch (error) {
287
- attempt++;
288
- Logger.error(`Attempt ${attempt} of ${maxRetries} failed in ${retryDelay[attempt - 1] / 1000}s...: ${(error as Error).message}`, 'publishMessageToExchange');
289
-
290
- if (attempt >= maxRetries) {
291
- Logger.error('Max retries reached. Sending message to Dead Letter Queue...', 'publishMessageToExchange');
292
- await this.sendToDeadLetterQueue({ message, attempt });
293
- Logger.error(`Failed to publish message to exchange ${exchangeName} after ${maxRetries} attempts`, 'publishMessageToExchange');
294
- return false;
295
- }
296
-
297
- // Exponential backoff using TTL array
298
- const delay = retryDelay[attempt - 1] ?? retryDelay[retryDelay.length - 1];
299
- Logger.info(`Retrying in ${delay / 1000}s...`, 'publishMessageToExchange');
300
- await new Promise(res => setTimeout(res, delay));
301
- }
302
- }
303
-
304
- return false;
305
- }
306
-
307
- /**
308
- * Description: Publishes a message directly to a RabbitMQ queue with configurable retry attempts.
309
- * On each failed attempt, waits using exponential backoff based on TTL config.
310
- * After all retries are exhausted, sends the message to the dead letter queue.
311
- * @param request - The request object containing the queue name and the message payload
312
- * @returns true if the message was published successfully, false otherwise
313
- */
314
- public async publishMessage(request: { queueName: string; message: any }): Promise<boolean> {
315
- Logger.info('Reached to publishMessage', 'publishMessage');
316
- const { queueName, message } = request;
317
- const retryDelayConfig = message?.message?.feed_type === RABBITMQ_FEED_TYPE.OVR ? RABBITMQ.OVR_TTL : RABBITMQ.ETX_TTL;
318
- const retryDelay = retryDelayConfig.split('|').map(Number);
319
-
320
- let attempt = 0;
321
- while (attempt < maxRetries) {
322
- try {
323
- await this.checkConnectionAndChannel();
324
- const messageBuffer = Buffer.from(JSON.stringify(message));
325
- const sent = this.channel!.sendToQueue(queueName, messageBuffer, { persistent: true });
326
- //if(attempt < 1){ sent = false}else{sent = true} // --- IGNORE ---
327
- if (sent && (RABBITMQ.PUBLISHER_RETRY_ERROR !== 'true' && RABBITMQ.PUBLISHER_RETRY_ERROR !== true)) {
328
- Logger.info(`Message published successfully on attempt ${attempt + 1}`, 'publishMessage');
329
- return true;
330
- } else {
331
- throw new Error('Channel publish returned false — buffer full');
332
- }
333
- } catch (error) {
334
- attempt++;
335
- Logger.error(`Attempt ${attempt} of ${maxRetries} failed in ${retryDelay[attempt - 1] / 1000}s...: ${(error as Error).message}`, 'publishMessage');
336
-
337
- if (attempt >= maxRetries) {
338
- Logger.error('Max retries reached. Sending message to Dead Letter Queue...', 'publishMessage');
339
- await this.sendToDeadLetterQueue({ message, attempt });
340
- Logger.error(`Failed to publish message to queue ${queueName} after ${maxRetries} attempts`, 'publishMessage');
341
- return false;
342
- }
343
-
344
- // Exponential backoff using TTL array
345
- const delay = retryDelay[attempt - 1] ?? retryDelay[retryDelay.length - 1];
346
- Logger.info(`Retrying in ${delay / 1000}s...`, 'publishMessage');
347
- await new Promise(res => setTimeout(res, delay));
348
- }
349
- }
350
-
351
- return false;
352
- }
353
-
354
- /**
355
- * Description: Sends a failed message to the dead letter queue after all retries are exhausted.
356
- * @param request - The request object containing the message payload and the number of attempts made
357
- */
358
- private async sendToDeadLetterQueue(request: { message: any; attempt: number }): Promise<void> {
359
- const { message, attempt } = request;
360
- try {
361
- await this.checkConnectionAndChannel(); // Ensure connection and channel are alive before sending to DLQ
362
- const dlqQueue = RABBITMQ.DLX_QUEUE_ETG;
363
- const messageBuffer = Buffer.from(JSON.stringify(message));
364
- const sent = this.channel!.sendToQueue(dlqQueue, messageBuffer, {
365
- persistent: true,
366
- headers: { 'x-retry-count': attempt },
367
- });
368
- if (sent) {
369
- Logger.info(`Message sent to DLQ: ${dlqQueue} (attempts: ${attempt})`, 'sendToDeadLetterQueue');
370
- } else {
371
- Logger.error(`Failed to send message to DLQ: ${dlqQueue} — buffer full`, 'sendToDeadLetterQueue');
372
- }
373
- } catch (error) {
374
- Logger.error(`Error sending message to DLQ: ${(error as Error).message}`, 'sendToDeadLetterQueue');
375
- }
376
- }
377
-
378
- /**
379
- * Description: Initializes consumers for all queues listed in `consume_queues` config.
380
- * @param classInstance - Object whose methods will be called as handlers
381
- * @param consumerHandler - Method name on classInstance to process each message
382
- * @param consumerErrorHandler - Method name on classInstance called when all retries fail
383
- */
384
- public async initializeConsumers(classInstance: any, consumerHandler: string, consumerErrorHandler: string): Promise<void> {
385
- try {
386
- Logger.info('Reached in initialize consumers', 'initializeConsumers');
387
- const consumeQueues = configData?.consume_queues;
388
- for (const queueName in consumeQueues) {
389
- if (Object.prototype.hasOwnProperty.call(consumeQueues, queueName)) {
390
- await this.consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler);
391
- }
392
- }
393
- } catch (error: unknown) {
394
- Logger.error('Error initializing consumers:', 'initializeConsumers', (error as Error).message);
395
- throw new Error((error as Error).message);
396
- }
397
- }
398
-
399
- /**
400
- * Description: Consumes messages from a queue with retry logic.
401
- * - Success → ack
402
- * - Failure + retries left → send to retry queue with incremented x-retry-count & TTL backoff, ack original
403
- * - Failure + retries exhausted → DLQ + error handler + nack (no requeue)
404
- * - Unhandled exception → DLQ + error handler + nack
405
- * @param queueName - Queue to consume from
406
- * @param classInstance - Object whose methods will be called as handlers
407
- * @param consumerHandler - Method name invoked to process each message
408
- * @param consumerErrorHandler - Method name invoked when all retries fail
409
- */
410
- public async consumeMessage(
411
- queueName: string,
412
- classInstance: any,
413
- consumerHandler: string,
414
- consumerErrorHandler: string
415
- ): Promise<void> {
416
- Logger.info(`Reached: Consuming messages from queue ${queueName}`, 'consumeMessage');
417
-
418
- await this.checkConnectionAndChannel();
419
-
420
- await this.channel!.consume(queueName, async (message: any) => {
421
- if (!message) return;
422
-
423
- const msgData: any = JSON.parse(message.content.toString());
424
- const headers = message.properties.headers || {};
425
- const retryCount: number = headers['x-retry-count'] || 0;
426
-
427
- const feedType = msgData?.message?.feed_type ?? msgData?.feed_type;
428
- const retryDelayTTL = feedType === RABBITMQ_FEED_TYPE.OVR ? RABBITMQ.OVR_TTL : RABBITMQ.ETX_TTL;
429
- const retryDelay:any = retryDelayTTL.split('|').map(Number);
430
-
431
- const data: any = {
432
- queue_name: queueName,
433
- body: msgData?.message?.body ?? msgData?.body,
434
- trace: msgData?.message?.trace ?? msgData?.trace,
435
- retries: msgData?.message?.retries ?? msgData?.retries,
436
- version: msgData?.message?.version ?? msgData?.version,
437
- feed_type: msgData?.message?.feed_type ?? msgData?.feed_type,
438
- };
439
-
440
- try {
441
- let success: any = {};
442
-
443
- if (RABBITMQ.CONSUMER_RETRY_ERROR !== 'true' && RABBITMQ.CONSUMER_RETRY_ERROR !== true) {
444
- if (typeof classInstance[consumerHandler] === 'function') {
445
- Logger.info('Consumer handler call for processing the request', 'consumeMessage');
446
- success = await classInstance[consumerHandler]({ queueName, message: msgData });
447
- } else {
448
- Logger.error(`Method ${consumerHandler} not found on classInstance`, 'consumeMessage');
449
- }
450
- }
451
- if(success?.isMatch === true){
452
- if (success?.status) {
453
- Logger.info('Acknowledge the successful processing', 'consumeMessage');
454
- this.channel!.ack(message);
455
- } else {
456
- if (retryCount >= maxRetries) {
457
- Logger.error('Max retries reached. Sending message to Dead Letter Queue.', 'consumeMessage');
458
- await this.sendToDeadLetterQueue({ message: data, attempt: retryCount });
459
-
460
- if (typeof classInstance[consumerErrorHandler] === 'function') {
461
- classInstance[consumerErrorHandler](data);
462
- } else {
463
- Logger.error(`Method ${consumerErrorHandler} not found on classInstance`, 'consumeMessage');
464
- }
465
- this.channel!.nack(message, false, false);
466
- } else {
467
- const nextAttempt = retryCount + 1;
468
- if (data?.retries >= 0) {
469
- data.retries = nextAttempt;
470
- }
471
- const delayIndex = nextAttempt - 1 < retryDelay.length ? nextAttempt - 1 : retryDelay.length - 1;
472
- const delay = Number(retryDelay[delayIndex]);
473
- Logger.info(`Retrying in ${delay / 1000} seconds... (attempt ${nextAttempt} of ${maxRetries} ${data.feed_type})`, 'consumeMessage');
474
- await this.sendMessageToRetryQueue({ attempt: nextAttempt, data, retryDelayMs: delay, queueName });
475
- this.channel!.ack(message);
476
- }
477
- }
478
- }
479
- } catch (error) {
480
- Logger.error('Error processing message', 'consumeMessage', { message: (error as Error).message });
481
- await this.sendToDeadLetterQueue({ message: data, attempt: retryCount });
482
-
483
- if (typeof classInstance[consumerErrorHandler] === 'function') {
484
- classInstance[consumerErrorHandler](data);
485
- } else {
486
- Logger.error(`Method ${consumerErrorHandler} not found on classInstance`, 'consumeMessage');
487
- }
488
- this.channel!.nack(message, false, false);
489
- }
490
- });
491
- }
492
-
493
- /**
494
- * Description: Sends a message to a retry queue with an incremented retry count and appropriate TTL for delayed reprocessing.
495
- * @param request
496
- * @returns boolean indicating if the message was sent to the retry queue successfully
497
- */
498
- private async sendMessageToRetryQueue(request: { attempt: number; data: any; retryDelayMs: number; queueName: string }): Promise<boolean> {
499
- const { attempt, data, retryDelayMs, queueName } = request;
500
- Logger.info(`Sending message to retry queue: ${queueName} (attempt: ${attempt}, delay: ${retryDelayMs}ms)`, 'sendMessageToRetryQueue');
501
- try {
502
- await this.checkConnectionAndChannel();
503
- const retryQueueName = RABBITMQ.DLX_QUEUE_ETG_RETRY;
504
- const messageBuffer = Buffer.from(JSON.stringify(data));
505
- const sent = this.channel!.sendToQueue(retryQueueName, messageBuffer, {
506
- headers: {
507
- 'x-retry-count': attempt,
508
- toQueue: queueName,
509
- },
510
- expiration: retryDelayMs.toString(),
511
- persistent: true,
512
- mandatory: true
513
- });
514
- if (sent) {
515
- Logger.info(`Message sent to retry queue: ${queueName} (attempt: ${attempt})`, 'sendMessageToRetryQueue');
516
- } else {
517
- Logger.error(`Failed to send message to retry queue: ${queueName} — buffer full`, 'sendMessageToRetryQueue');
518
- }
519
- return sent;
520
- } catch (error) {
521
- Logger.error(`Error sending message to retry queue: ${(error as Error).message}`, 'sendMessageToRetryQueue');
522
- throw error;
523
- }
524
- }
525
- }