@onlineapps/service-wrapper 2.0.48 → 2.0.50
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/package.json +1 -1
- package/src/ServiceWrapper.js +108 -1
package/package.json
CHANGED
package/src/ServiceWrapper.js
CHANGED
|
@@ -485,6 +485,11 @@ class ServiceWrapper {
|
|
|
485
485
|
console.warn('Monitoring initialization failed (non-critical):', error.message);
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
|
+
|
|
489
|
+
// Register MQ channel close hooks and health monitoring AFTER monitoring is initialized
|
|
490
|
+
if (this.mqClient) {
|
|
491
|
+
await this._registerMQHooks();
|
|
492
|
+
}
|
|
488
493
|
|
|
489
494
|
// Initialize cache if configured
|
|
490
495
|
if (this.config.wrapper?.cache?.enabled === true) {
|
|
@@ -557,6 +562,68 @@ class ServiceWrapper {
|
|
|
557
562
|
}
|
|
558
563
|
}
|
|
559
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Register MQ channel close hooks and health monitoring
|
|
567
|
+
* Must be called AFTER monitoring is initialized
|
|
568
|
+
* @private
|
|
569
|
+
*/
|
|
570
|
+
async _registerMQHooks() {
|
|
571
|
+
if (!this.mqClient || !this.mqClient._transport) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Access the underlying transport (RabbitMQClient) to register hooks
|
|
576
|
+
const transport = this.mqClient._transport;
|
|
577
|
+
|
|
578
|
+
if (typeof transport.onChannelClose === 'function') {
|
|
579
|
+
// Register hook for all channel types
|
|
580
|
+
transport.onChannelClose('all', (details) => {
|
|
581
|
+
const logData = {
|
|
582
|
+
type: details.type,
|
|
583
|
+
reason: details.reason,
|
|
584
|
+
error: details.error ? {
|
|
585
|
+
message: details.error.message,
|
|
586
|
+
code: details.error.code,
|
|
587
|
+
stack: details.error.stack
|
|
588
|
+
} : null,
|
|
589
|
+
timestamp: details.timestamp,
|
|
590
|
+
connectionState: details.connectionState,
|
|
591
|
+
channelCreatedAt: details.channelCreatedAt,
|
|
592
|
+
lastOperation: details.lastOperation
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
if (this.monitoring && this.monitoring.error) {
|
|
596
|
+
this.monitoring.error(`MQ Channel Closed: ${details.type}`, logData);
|
|
597
|
+
}
|
|
598
|
+
console.error(`[ServiceWrapper] [MQ] Channel closed: ${details.type} - ${details.reason}`);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
this.logger?.info('MQ channel close hooks registered');
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Register health shutdown handler
|
|
605
|
+
if (typeof transport.on === 'function') {
|
|
606
|
+
transport.on('health:shutdown', (health) => {
|
|
607
|
+
console.error('[ServiceWrapper] [MQ] Health shutdown triggered - shutting down service');
|
|
608
|
+
if (this.monitoring && this.monitoring.error) {
|
|
609
|
+
this.monitoring.error('MQ Health Shutdown', {
|
|
610
|
+
issues: health.issues,
|
|
611
|
+
timestamp: health.timestamp
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
// Graceful shutdown
|
|
615
|
+
this.shutdown().then(() => {
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}).catch((err) => {
|
|
618
|
+
console.error('[ServiceWrapper] Shutdown error:', err);
|
|
619
|
+
process.exit(1);
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
this.logger?.info('MQ health shutdown handler registered');
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
560
627
|
/**
|
|
561
628
|
* Initialize MQ connection
|
|
562
629
|
* @private
|
|
@@ -569,6 +636,39 @@ class ServiceWrapper {
|
|
|
569
636
|
|
|
570
637
|
const serviceName = this.config.service?.name || 'unnamed-service';
|
|
571
638
|
|
|
639
|
+
// Health monitoring and channel close hooks configuration
|
|
640
|
+
const healthCheckConfig = {
|
|
641
|
+
healthCheckInterval: this.config.wrapper?.mq?.healthCheckInterval || 30000, // 30s
|
|
642
|
+
healthCheckEnabled: this.config.wrapper?.mq?.healthCheckEnabled !== false, // Default: true
|
|
643
|
+
criticalHealthShutdown: this.config.wrapper?.mq?.criticalHealthShutdown !== false, // Default: true
|
|
644
|
+
criticalHealthShutdownDelay: this.config.wrapper?.mq?.criticalHealthShutdownDelay || 60000, // 60s
|
|
645
|
+
// Health reporting callbacks
|
|
646
|
+
healthReportCallback: async (health) => {
|
|
647
|
+
if (this.monitoring && this.monitoring.info) {
|
|
648
|
+
this.monitoring.info('MQ Health Check', {
|
|
649
|
+
healthy: health.healthy,
|
|
650
|
+
issues: health.issues,
|
|
651
|
+
consumers: health.consumers,
|
|
652
|
+
queues: health.queues,
|
|
653
|
+
channels: health.channels
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
},
|
|
657
|
+
healthCriticalCallback: async (health) => {
|
|
658
|
+
if (this.monitoring && this.monitoring.error) {
|
|
659
|
+
this.monitoring.error('MQ CRITICAL HEALTH', {
|
|
660
|
+
issues: health.issues,
|
|
661
|
+
consumers: health.consumers,
|
|
662
|
+
queues: health.queues,
|
|
663
|
+
channels: health.channels,
|
|
664
|
+
timestamp: health.timestamp
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
// Also log to console for visibility
|
|
668
|
+
console.error('[ServiceWrapper] [MQ] CRITICAL HEALTH:', health.issues);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
572
672
|
this.mqClient = new MQConnector({
|
|
573
673
|
type: 'rabbitmq',
|
|
574
674
|
host: mqUrl,
|
|
@@ -578,12 +678,19 @@ class ServiceWrapper {
|
|
|
578
678
|
prefetch: this.config.wrapper?.mq?.prefetch || 10,
|
|
579
679
|
durable: true,
|
|
580
680
|
noAck: false,
|
|
581
|
-
logger: this.logger || console
|
|
681
|
+
logger: this.logger || console,
|
|
682
|
+
...healthCheckConfig
|
|
582
683
|
});
|
|
583
684
|
|
|
685
|
+
// Register channel close hooks AFTER mqClient is created but BEFORE connect
|
|
686
|
+
// Access the underlying transport (RabbitMQClient) to register hooks
|
|
687
|
+
// Note: transport is created during connect(), so we need to register hooks after connect
|
|
688
|
+
// We'll do this in a separate method called after connect
|
|
689
|
+
|
|
584
690
|
try {
|
|
585
691
|
await this.mqClient.connect();
|
|
586
692
|
this.logger?.info('MQ connector initialized');
|
|
693
|
+
|
|
587
694
|
} catch (error) {
|
|
588
695
|
const message = `[MQConnector] Unable to connect to RabbitMQ at ${mqUrl}. ` +
|
|
589
696
|
'Verify that api_services_queuer is running and accessible. ' +
|