@platform-x/hep-message-broker-client 1.1.3 → 1.1.6

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