@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.
- package/dist/src/config/index.js +9 -8
- package/dist/src/messageBroker/rabbitmq/MessageBroker.js +76 -10
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +18 -187
- package/package.json +1 -1
- package/rabbitMQConfig.json +344 -0
- package/dist/src/Util/commonUtil.js.map +0 -1
- package/dist/src/Util/constants.js.map +0 -1
- package/dist/src/Util/logger.js.map +0 -1
- package/dist/src/Util/requestTracer.js.map +0 -1
- package/dist/src/config/ConfigManager.js.map +0 -1
- package/dist/src/config/index.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/messageBroker/BaseRabbitMQClient.js.map +0 -1
- package/dist/src/messageBroker/ConnectionManager.js.map +0 -1
- package/dist/src/messageBroker/MessageBrokerClient.js.map +0 -1
- package/dist/src/messageBroker/MessageConsumer.js.map +0 -1
- package/dist/src/messageBroker/MessageProducer.js.map +0 -1
- package/dist/src/messageBroker/RabbitMQClient.js.map +0 -1
- package/dist/src/messageBroker/RetryManager.js.map +0 -1
- package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +0 -1
- package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +0 -1
- package/dist/src/messageBroker/rabbitmq/MessageBroker.js.map +0 -1
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +0 -1
- package/dist/src/messageBroker/types/ActionType.js.map +0 -1
- package/dist/src/messageBroker/types/PublishMessageInputType.js.map +0 -1
- package/dist/src/models/MessageModel.js.map +0 -1
- package/dist/src/models/NotificationMessageModel.js.map +0 -1
- package/src/Util/commonUtil.ts +0 -41
- package/src/Util/constants.ts +0 -9
- package/src/Util/logger.ts +0 -219
- package/src/Util/requestTracer.ts +0 -28
- package/src/config/ConfigManager.ts +0 -35
- package/src/config/index.ts +0 -38
- package/src/index.ts +0 -74
- package/src/messageBroker/BaseRabbitMQClient.ts +0 -30
- package/src/messageBroker/ConnectionManager.ts +0 -182
- package/src/messageBroker/MessageBrokerClient.ts +0 -88
- package/src/messageBroker/MessageConsumer.ts +0 -85
- package/src/messageBroker/MessageProducer.ts +0 -142
- package/src/messageBroker/RabbitMQClient.ts +0 -47
- package/src/messageBroker/RetryManager.ts +0 -64
- package/src/messageBroker/interface/ConnectionWrapper.ts +0 -7
- package/src/messageBroker/interface/IMessageBrokerClient.ts +0 -11
- package/src/messageBroker/rabbitmq/MessageBroker.ts +0 -547
- package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +0 -855
- package/src/messageBroker/types/ActionType.ts +0 -1
- package/src/messageBroker/types/PublishMessageInputType.ts +0 -8
- package/src/models/MessageModel.ts +0 -14
- package/src/models/NotificationMessageModel.ts +0 -0
- package/tsconfig.json +0 -73
package/dist/src/config/index.js
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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(
|
|
486
|
-
return __awaiter(this,
|
|
487
|
-
logger_1.Logger.info(`Reached: Consuming messages from queue ${queueName}`, 'consumeMessage');
|
|
488
|
-
|
|
489
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|