@platform-x/hep-message-broker-client 1.1.28 → 1.1.29

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/config/index.js +9 -8
  2. package/dist/src/messageBroker/rabbitmq/MessageBroker.js +76 -10
  3. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +18 -187
  4. package/package.json +1 -1
  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 -547
  45. package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +0 -855
  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
@@ -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, _u, _v, _w, _x, _y;
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, _z, _0;
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const dotenv_1 = __importDefault(require("dotenv"));
8
8
  dotenv_1.default.config();
@@ -33,13 +33,14 @@ exports.default = {
33
33
  IS_ENABLED: (_p = process.env.RABBITMQ_IS_ENABLED) !== null && _p !== void 0 ? _p : 'true',
34
34
  RABBITMQ_CONFIG: (_q = process.env.RABBITMQ_CONFIG) !== null && _q !== void 0 ? _q : '',
35
35
  PREFETCH_COUNT: Number((_r = process.env.RABBITMQ_PREFETCH) !== null && _r !== void 0 ? _r : 50),
36
- CONNECTION_ERROR: (_s = process.env.RABBITMQ_CONNECTION_ERROR) !== null && _s !== void 0 ? _s : false,
37
- PUBLISHER_ERROR: (_t = process.env.RABBITMQ_PUBLISHER_ERROR) !== null && _t !== void 0 ? _t : false,
38
- CONSUMER_ERROR: (_u = process.env.RABBITMQ_CONSUMER_ERROR) !== null && _u !== void 0 ? _u : false,
39
- CONNECTION_RETRY_ERROR: (_v = process.env.RABBITMQ_RETRY_ENABLE_CONNECTION) !== null && _v !== void 0 ? _v : false,
40
- PUBLISHER_RETRY_ERROR: (_w = process.env.RABBITMQ_RETRY_ENABLE_PUBLISH) !== null && _w !== void 0 ? _w : false,
41
- CONSUMER_RETRY_ERROR: (_x = process.env.RABBITMQ_RETRY_ENABLE_CONSUMER) !== null && _x !== void 0 ? _x : false,
42
- CONFIG_PATH: (_y = process.env.CONFIG_PATH) !== null && _y !== void 0 ? _y : '/etc/rabbitmq/rabbitMQConfig.json',
36
+ PREFETCH_COUNT_OVR: Number((_t = (_s = process.env.RABBITMQ_PREFETCH_OVR) !== null && _s !== void 0 ? _s : process.env.RABBITMQ_PREFETCH) !== null && _t !== void 0 ? _t : 50),
37
+ CONNECTION_ERROR: (_u = process.env.RABBITMQ_CONNECTION_ERROR) !== null && _u !== void 0 ? _u : false,
38
+ PUBLISHER_ERROR: (_v = process.env.RABBITMQ_PUBLISHER_ERROR) !== null && _v !== void 0 ? _v : false,
39
+ CONSUMER_ERROR: (_w = process.env.RABBITMQ_CONSUMER_ERROR) !== null && _w !== void 0 ? _w : false,
40
+ CONNECTION_RETRY_ERROR: (_x = process.env.RABBITMQ_RETRY_ENABLE_CONNECTION) !== null && _x !== void 0 ? _x : false,
41
+ PUBLISHER_RETRY_ERROR: (_y = process.env.RABBITMQ_RETRY_ENABLE_PUBLISH) !== null && _y !== void 0 ? _y : false,
42
+ CONSUMER_RETRY_ERROR: (_z = process.env.RABBITMQ_RETRY_ENABLE_CONSUMER) !== null && _z !== void 0 ? _z : false,
43
+ CONFIG_PATH: (_0 = process.env.CONFIG_PATH) !== null && _0 !== void 0 ? _0 : '/etc/rabbitmq/rabbitMQConfig.json',
43
44
  }
44
45
  };
45
46
  //# sourceMappingURL=index.js.map
@@ -63,6 +63,7 @@ class MessageBroker {
63
63
  constructor() {
64
64
  this.connection = null;
65
65
  this.channel = null;
66
+ this.consumerChannels = new Map();
66
67
  }
67
68
  /**
68
69
  * Description: Checks if the RabbitMQ connection and channel are established.
@@ -458,12 +459,20 @@ class MessageBroker {
458
459
  return __awaiter(this, void 0, void 0, function* () {
459
460
  try {
460
461
  logger_1.Logger.info('Reached in initialize consumers', 'initializeConsumers');
461
- const consumeQueues = configData === null || configData === void 0 ? void 0 : configData.etg_consume_queues;
462
+ const consumeQueues = configData === null || configData === void 0 ? void 0 : configData.etg_consume_queues; // for etx feed
463
+ const consumesQueuesOVR = configData === null || configData === void 0 ? void 0 : configData.etg_consume_queues_ovr; // for ovr feed
464
+ // etx Queue
462
465
  for (const queueName in consumeQueues) {
463
466
  if (Object.prototype.hasOwnProperty.call(consumeQueues, queueName)) {
464
467
  yield this.consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler);
465
468
  }
466
469
  }
470
+ // OVR Queues
471
+ for (const queueName in consumesQueuesOVR) {
472
+ if (Object.prototype.hasOwnProperty.call(consumesQueuesOVR, queueName)) {
473
+ yield this.consumeMessageOVR(queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler);
474
+ }
475
+ }
467
476
  }
468
477
  catch (error) {
469
478
  logger_1.Logger.error('Error initializing consumers:', 'initializeConsumers', error.message);
@@ -471,6 +480,61 @@ class MessageBroker {
471
480
  }
472
481
  });
473
482
  }
483
+ /**
484
+ * Description: Creates (or replaces) a dedicated channel for consuming a single queue and
485
+ * applies the given prefetch. Each consumer gets its own channel so its prefetch window and
486
+ * ack/nack traffic are isolated from other consumers and from the shared publish channel.
487
+ * @param queueName - Queue this channel will consume from (used as the tracking key)
488
+ * @param prefetch - Max unacknowledged messages allowed in flight on this channel
489
+ * @returns The dedicated consumer channel
490
+ */
491
+ createConsumerChannel(queueName, prefetch) {
492
+ return __awaiter(this, void 0, void 0, function* () {
493
+ yield this.checkConnectionAndChannel(); // Ensure the underlying connection is alive
494
+ // Replace any stale channel for this queue to avoid duplicate consumers.
495
+ const existing = this.consumerChannels.get(queueName);
496
+ if (existing) {
497
+ try {
498
+ yield existing.close();
499
+ }
500
+ catch ( /* already closed */_a) { /* already closed */ }
501
+ this.consumerChannels.delete(queueName);
502
+ }
503
+ const consumerChannel = yield this.connection.createChannel();
504
+ yield consumerChannel.prefetch(prefetch);
505
+ consumerChannel.on('error', (err) => {
506
+ logger_1.Logger.error(`Consumer channel error for ${queueName}: ${err.message}`, 'createConsumerChannel');
507
+ });
508
+ consumerChannel.on('close', () => {
509
+ this.consumerChannels.delete(queueName);
510
+ });
511
+ this.consumerChannels.set(queueName, consumerChannel);
512
+ logger_1.Logger.info(`Dedicated consumer channel created for ${queueName} (prefetch: ${prefetch})`, 'createConsumerChannel');
513
+ return consumerChannel;
514
+ });
515
+ }
516
+ /**
517
+ * consumeMessageOVR is a specialized consumer for OVR queues. It delegates to consumeMessage to handle the actual message processing, retry logic, and error handling.
518
+ * @param queueName
519
+ * @param classInstance
520
+ * @param consumerHandler
521
+ * @param consumerErrorHandler
522
+ * @param consumerRetryHandler
523
+ */
524
+ consumeMessageOVR(queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler) {
525
+ return __awaiter(this, void 0, void 0, function* () {
526
+ try {
527
+ logger_1.Logger.info('Reached in consumeMessageOVR', 'consumeMessageOVR');
528
+ // OVR consumption uses the same retry/ack/nack pipeline as consumeMessage; delegate to avoid
529
+ // duplicated logic, but with an OVR-specific prefetch so it can be tuned independently of ETX.
530
+ yield this.consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler, RABBITMQ.PREFETCH_COUNT_OVR);
531
+ }
532
+ catch (error) {
533
+ logger_1.Logger.error('Error consuming messages from OVR queue:', 'consumeMessageOVR', error.message);
534
+ throw new Error(error.message);
535
+ }
536
+ });
537
+ }
474
538
  /**
475
539
  * Description: Consumes messages from a queue with retry logic.
476
540
  * - Success → ack
@@ -482,11 +546,13 @@ class MessageBroker {
482
546
  * @param consumerHandler - Method name invoked to process each message
483
547
  * @param consumerErrorHandler - Method name invoked when all retries fail
484
548
  */
485
- consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler) {
486
- return __awaiter(this, void 0, void 0, function* () {
487
- logger_1.Logger.info(`Reached: Consuming messages from queue ${queueName}`, 'consumeMessage');
488
- yield this.checkConnectionAndChannel();
489
- yield this.channel.consume(queueName, (message) => __awaiter(this, void 0, void 0, function* () {
549
+ consumeMessage(queueName_1, classInstance_1, consumerHandler_1, consumerErrorHandler_1, consumerRetryHandler_1) {
550
+ return __awaiter(this, arguments, void 0, function* (queueName, classInstance, consumerHandler, consumerErrorHandler, consumerRetryHandler, prefetch = prefetchCount) {
551
+ logger_1.Logger.info(`Reached: Consuming messages from queue ${queueName} (prefetch: ${prefetch})`, 'consumeMessage');
552
+ // Consume on a dedicated channel so this queue's prefetch window and
553
+ // ack/nack traffic are isolated from other consumers/publishers.
554
+ const consumerChannel = yield this.createConsumerChannel(queueName, prefetch);
555
+ yield consumerChannel.consume(queueName, (message) => __awaiter(this, void 0, void 0, function* () {
490
556
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
491
557
  if (!message)
492
558
  return;
@@ -518,7 +584,7 @@ class MessageBroker {
518
584
  if ((success === null || success === void 0 ? void 0 : success.isMatch) === true) {
519
585
  if (success === null || success === void 0 ? void 0 : success.status) {
520
586
  logger_1.Logger.info('Acknowledge the successful processing', 'consumeMessage');
521
- this.channel.ack(message);
587
+ consumerChannel.ack(message);
522
588
  }
523
589
  else {
524
590
  if (retryCount >= maxRetries) {
@@ -530,7 +596,7 @@ class MessageBroker {
530
596
  else {
531
597
  logger_1.Logger.error(`Method ${consumerErrorHandler} not found on classInstance`, 'consumeMessage');
532
598
  }
533
- this.channel.nack(message, false, false);
599
+ consumerChannel.nack(message, false, false);
534
600
  }
535
601
  else {
536
602
  const nextAttempt = retryCount + 1;
@@ -548,7 +614,7 @@ class MessageBroker {
548
614
  else {
549
615
  logger_1.Logger.error(`Method ${consumerRetryHandler} not found on classInstance`, 'consumeMessage');
550
616
  }
551
- this.channel.ack(message);
617
+ consumerChannel.ack(message);
552
618
  }
553
619
  }
554
620
  }
@@ -562,7 +628,7 @@ class MessageBroker {
562
628
  else {
563
629
  logger_1.Logger.error(`Method ${consumerErrorHandler} not found on classInstance`, 'consumeMessage');
564
630
  }
565
- this.channel.nack(message, false, false);
631
+ consumerChannel.nack(message, false, false);
566
632
  }
567
633
  }));
568
634
  });
@@ -71,10 +71,6 @@ let dlx_queue = RABBITMQ.DLX_QUEUE;
71
71
  // let retry_queue:string = RABBITMQ.RETRY_QUEUE;
72
72
  let connectionRetry = 1;
73
73
  let retryCountHeader = 'x-retry-count';
74
- let registeredConsumers = new Map();
75
- // Guards handleReconnect() so overlapping close/error events don't spawn
76
- // multiple concurrent reconnect loops.
77
- let isReconnecting = false;
78
74
  class MessageBrokerClient {
79
75
  // private readonly correlationId: string;
80
76
  // constructor() {
@@ -336,35 +332,9 @@ class MessageBrokerClient {
336
332
  consumeMessage(queueName, classInstance, consumerHandler, consumerErrorHandler) {
337
333
  return __awaiter(this, void 0, void 0, function* () {
338
334
  logger_1.Logger.info("Reached: Consuming messages from the queue", 'consumeMessage');
339
- // Remember this consumer so it can be re-attached after any reconnect or
340
- // channel recreation. Keyed by queueName so repeated calls don't stack.
341
- registeredConsumers.set(queueName, { queueName, classInstance, consumerHandler, consumerErrorHandler });
342
- return yield this.subscribeConsumer(queueName, classInstance, consumerHandler, consumerErrorHandler);
343
- });
344
- }
345
- ;
346
- /**
347
- * Function to attach a single consumer to a queue. Performs the actual
348
- * channel.consume() and owns the ack/retry/DLQ logic. Kept separate from
349
- * consumeMessage() so re-subscription (on reconnect) does not re-register
350
- * the consumer in the registry, which would grow it unboundedly.
351
- * @param queueName
352
- * @param classInstance
353
- * @param consumerHandler
354
- * @param consumerErrorHandler
355
- */
356
- subscribeConsumer(queueName, classInstance, consumerHandler, consumerErrorHandler) {
357
- return __awaiter(this, void 0, void 0, function* () {
358
335
  let attempt = 0;
359
336
  if (isConnectionOpen) {
360
- // Capture the channel this consumer is registered on. acks/nacks for
361
- // messages delivered here MUST go back to this same channel object —
362
- // if the module-level `channel` is later reassigned (recreateChannel /
363
- // createConnection), acking against the new channel raises
364
- // PRECONDITION_FAILED ("unknown delivery tag") and closes it, taking
365
- // every consumer down with it.
366
- const ch = channel;
367
- return yield ch.consume(queueName, (message) => __awaiter(this, void 0, void 0, function* () {
337
+ return yield channel.consume(queueName, (message) => __awaiter(this, void 0, void 0, function* () {
368
338
  var _a;
369
339
  if (message) {
370
340
  logger_1.Logger.info(`Message received from queue ${queueName}: ${JSON.stringify(message)}`, 'consumeMessage');
@@ -401,7 +371,7 @@ class MessageBrokerClient {
401
371
  else {
402
372
  logger_1.Logger.info(`Method ${consumerErrorHandler} not found in classInstance.`, 'consumerMessage');
403
373
  }
404
- this.safeNack(ch, message); // Move message to DLQ after failure
374
+ channel.nack(message, false, false); // Move message to DLQ after failure
405
375
  return false;
406
376
  }
407
377
  attempt++;
@@ -414,19 +384,13 @@ class MessageBrokerClient {
414
384
  retryDelay = Number(count);
415
385
  yield this.sendMessageToRetryQueue(attempt, data, retryDelay, queueName);
416
386
  logger_1.Logger.info(`Retrying in ${retryDelay / 1000} seconds...`, 'consumeMessage');
417
- // Ack immediately once the message is safely on the retry
418
- // queue. Do NOT block the delivery for the full TTL — the
419
- // delay is enforced by the retry queue's own expiration.
420
- // Holding it here risks breaching RabbitMQ's
421
- // consumer_timeout and getting the channel cancelled.
422
- this.safeAck(ch, message);
423
- return;
387
+ yield new Promise((resolve) => setTimeout(resolve, retryDelay));
424
388
  }
425
389
  else {
426
390
  logger_1.Logger.info(`Acknowledge the successful processing`, 'consumeMessage');
427
391
  }
428
392
  // Acknowledge the successful processing
429
- this.safeAck(ch, message);
393
+ channel.ack(message);
430
394
  }
431
395
  }
432
396
  catch (error) {
@@ -440,7 +404,7 @@ class MessageBrokerClient {
440
404
  else {
441
405
  logger_1.Logger.info(`Method ${consumerErrorHandler} not found in classInstance.`, 'consumerMessage');
442
406
  }
443
- this.safeNack(ch, message); // Move message to DLQ after failure
407
+ channel.nack(message, false, false); // Move message to DLQ after failure
444
408
  }
445
409
  }
446
410
  }));
@@ -448,57 +412,6 @@ class MessageBrokerClient {
448
412
  });
449
413
  }
450
414
  ;
451
- /**
452
- * Function to re-attach every registered consumer. Called after each
453
- * successful (re)connect and after a channel is recreated, so queues never
454
- * end up with the connection alive but no consumer attached.
455
- */
456
- reregisterConsumers() {
457
- return __awaiter(this, void 0, void 0, function* () {
458
- if (registeredConsumers.size === 0) {
459
- return;
460
- }
461
- logger_1.Logger.info(`Re-subscribing ${registeredConsumers.size} consumer(s) after (re)connect`, 'reregisterConsumers');
462
- for (const c of registeredConsumers.values()) {
463
- try {
464
- yield this.subscribeConsumer(c.queueName, c.classInstance, c.consumerHandler, c.consumerErrorHandler);
465
- logger_1.Logger.info(`Consumer re-subscribed on queue ${c.queueName}`, 'reregisterConsumers');
466
- }
467
- catch (error) {
468
- logger_1.Logger.error(`Failed to re-subscribe consumer on queue ${c.queueName}`, 'reregisterConsumers', error.message);
469
- }
470
- }
471
- });
472
- }
473
- /**
474
- * Function to ack a message against the channel it was delivered on, guarded
475
- * so a stale delivery tag (channel already replaced) cannot throw and take
476
- * down the current channel.
477
- * @param ch the channel the message was consumed on
478
- * @param message
479
- */
480
- safeAck(ch, message) {
481
- try {
482
- ch.ack(message);
483
- }
484
- catch (error) {
485
- logger_1.Logger.error('Failed to ack message (stale channel?)', 'safeAck', error.message);
486
- }
487
- }
488
- /**
489
- * Function to nack a message against the channel it was delivered on, guarded
490
- * against stale delivery tags. Never requeues (routes to DLQ).
491
- * @param ch the channel the message was consumed on
492
- * @param message
493
- */
494
- safeNack(ch, message) {
495
- try {
496
- ch.nack(message, false, false);
497
- }
498
- catch (error) {
499
- logger_1.Logger.error('Failed to nack message (stale channel?)', 'safeNack', error.message);
500
- }
501
- }
502
415
  // /**
503
416
  // * Function for consumer massage handler
504
417
  // * @param request
@@ -792,17 +705,9 @@ class MessageBrokerClient {
792
705
  // create channel
793
706
  channel = yield connection.createConfirmChannel();
794
707
  channel.prefetch(RABBITMQ === null || RABBITMQ === void 0 ? void 0 : RABBITMQ.PREFETCH_COUNT);
795
- // Watch the channel itself: a channel-level fault (e.g. PRECONDITION_FAILED
796
- // from a stale ack) closes the channel and cancels its consumers without
797
- // closing the connection, so the connection 'close' path never fires.
798
- this.bindChannelEventHandler();
799
708
  logger_1.Logger.info('RabbitMQ connected successfully! ', 'createConnection');
800
709
  // create exchange and queue and bind with exchange
801
710
  yield this.setupQueuesAndExchanges();
802
- // Re-attach any consumers registered before this (re)connect. Without
803
- // this, after a reconnect the connection is healthy but no consumer is
804
- // bound to the queues — the root cause of consumers "disappearing".
805
- yield this.reregisterConsumers();
806
711
  const connectionWrapper = { connection, channel };
807
712
  return connectionWrapper;
808
713
  }
@@ -819,17 +724,21 @@ class MessageBrokerClient {
819
724
  */
820
725
  bindConnectionEventHandler() {
821
726
  try {
822
- // 'error' always precedes 'close' from amqplib, so only 'close' drives the
823
- // reconnect to avoid triggering it twice.
824
- connection.on('error', (err) => {
825
- var _a;
826
- logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:error`, `Connection error`, (_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err);
827
- });
828
727
  connection.on('close', (err) => __awaiter(this, void 0, void 0, function* () {
829
- var _a;
830
- logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, (_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err);
728
+ logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, err);
831
729
  isConnectionOpen = false;
832
- yield this.handleReconnect();
730
+ if (connectionRetry <= maxRetries) {
731
+ yield this.createConnection();
732
+ connectionRetry++;
733
+ }
734
+ }));
735
+ connection.on('error', (err) => __awaiter(this, void 0, void 0, function* () {
736
+ logger_1.Logger.error(`RabbitMQ: bindConnectionEventHandler:error`, `Connection error`, err);
737
+ isConnectionOpen = false;
738
+ if (connectionRetry <= maxRetries) {
739
+ yield this.createConnection();
740
+ connectionRetry++;
741
+ }
833
742
  }));
834
743
  return isConnectionOpen;
835
744
  }
@@ -838,84 +747,6 @@ class MessageBrokerClient {
838
747
  return isConnectionOpen;
839
748
  }
840
749
  }
841
- /**
842
- * Function to bind channel-level event handlers. A channel can be cancelled
843
- * (e.g. PRECONDITION_FAILED, consumer_timeout) while the connection stays up;
844
- * in that case the connection 'close' handler never fires, so the channel is
845
- * recreated and consumers re-attached here.
846
- */
847
- bindChannelEventHandler() {
848
- try {
849
- channel.on('error', (err) => {
850
- var _a;
851
- logger_1.Logger.error(`RabbitMQ: bindChannelEventHandler:error`, `Channel error`, (_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err);
852
- });
853
- channel.on('close', () => __awaiter(this, void 0, void 0, function* () {
854
- logger_1.Logger.error(`RabbitMQ: bindChannelEventHandler:close`, `Channel closed`);
855
- // Only self-heal the channel while the connection is still open. If the
856
- // connection is down, handleReconnect() owns recovery (and will recreate
857
- // the channel + consumers), so doing it here too would double-subscribe.
858
- if (isConnectionOpen && !isReconnecting) {
859
- try {
860
- yield this.recreateChannel();
861
- this.bindChannelEventHandler();
862
- yield this.reregisterConsumers();
863
- logger_1.Logger.info('Channel and consumers recovered after channel close', 'bindChannelEventHandler');
864
- }
865
- catch (error) {
866
- logger_1.Logger.error('Failed to recover channel after close', 'bindChannelEventHandler', error.message);
867
- }
868
- }
869
- }));
870
- }
871
- catch (error) {
872
- logger_1.Logger.error('Error in bindChannelEventHandler', 'bindChannelEventHandler', error.message);
873
- }
874
- }
875
- /**
876
- * Function to reconnect to RabbitMQ with capped exponential backoff. Unlike
877
- * the old logic — which capped total lifetime reconnects at MAX_RETRIES and
878
- * never reset the counter — this retries indefinitely and resets on success,
879
- * so the service self-heals from every disconnect. createConnection()
880
- * re-attaches all registered consumers on success.
881
- */
882
- handleReconnect() {
883
- return __awaiter(this, void 0, void 0, function* () {
884
- var _a;
885
- if (isReconnecting) {
886
- logger_1.Logger.info('Reconnect already in progress, skipping duplicate trigger', 'handleReconnect');
887
- return;
888
- }
889
- isReconnecting = true;
890
- connectionRetry = 1;
891
- // Backoff schedule derived from the TTL config, capped at its last value.
892
- const backoffs = (retry_delay !== null && retry_delay !== void 0 ? retry_delay : []).map(Number).filter((n) => !Number.isNaN(n) && n > 0);
893
- const maxBackoff = backoffs.length ? backoffs[backoffs.length - 1] : 30000;
894
- try {
895
- while (!isConnectionOpen) {
896
- const delay = (_a = backoffs[connectionRetry - 1]) !== null && _a !== void 0 ? _a : maxBackoff;
897
- logger_1.Logger.info(`Reconnect attempt ${connectionRetry} in ${delay / 1000}s...`, 'handleReconnect');
898
- yield new Promise(resolve => setTimeout(resolve, delay));
899
- try {
900
- yield this.createConnection();
901
- if (isConnectionOpen) {
902
- connectionRetry = 1;
903
- logger_1.Logger.info('Reconnected to RabbitMQ successfully', 'handleReconnect');
904
- return;
905
- }
906
- throw new Error('createConnection did not establish an open connection');
907
- }
908
- catch (error) {
909
- logger_1.Logger.error(`Reconnect attempt ${connectionRetry} failed`, 'handleReconnect', error.message);
910
- connectionRetry++;
911
- }
912
- }
913
- }
914
- finally {
915
- isReconnecting = false;
916
- }
917
- });
918
- }
919
750
  }
920
751
  exports.MessageBrokerClient = MessageBrokerClient;
921
752
  //# sourceMappingURL=MessageBrokerClient.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platform-x/hep-message-broker-client",
3
- "version": "1.1.28",
3
+ "version": "1.1.29",
4
4
  "description": "platform-x hep-message-broker service",
5
5
  "main": "./dist/src/index.js",
6
6
  "scripts": {