UNPKG

@logistically/events-nestjs

Version:

NestJS integration for @logistically/events v3 - Event-driven architecture with Redis Streams

165 lines (164 loc) 7.46 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var PerformanceMonitorService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.PerformanceMonitorService = void 0; const common_1 = require("@nestjs/common"); const event_metadata_explorer_service_1 = require("./event-metadata-explorer.service"); const event_discovery_service_1 = require("./event-discovery.service"); let PerformanceMonitorService = PerformanceMonitorService_1 = class PerformanceMonitorService { constructor(metadataExplorer, eventDiscoveryService) { this.metadataExplorer = metadataExplorer; this.eventDiscoveryService = eventDiscoveryService; this.logger = new common_1.Logger(PerformanceMonitorService_1.name); this.startTime = Date.now(); this.processingTimes = []; this.lastDiscoveryRun = 0; } async onModuleInit() { this.logger.log('PerformanceMonitorService initialized'); // Start periodic performance reporting this.startPerformanceReporting(); } /** * Get comprehensive performance metrics */ getMetrics() { const cacheStats = this.metadataExplorer.getCacheStats(); const discoveryStats = this.eventDiscoveryService.getDiscoveryStats(); const memoryUsage = process.memoryUsage(); const avgProcessingTime = this.processingTimes.length > 0 ? this.processingTimes.reduce((a, b) => a + b, 0) / this.processingTimes.length : 0; return { cache: { hits: cacheStats.hits, misses: cacheStats.misses, hitRate: cacheStats.hitRate, }, discovery: { pending: discoveryStats.pending, registered: discoveryStats.registered, retryCount: discoveryStats.retryCount, processingTime: avgProcessingTime, }, memory: { heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024 * 100) / 100, // MB heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024 * 100) / 100, // MB external: Math.round(memoryUsage.external / 1024 / 1024 * 100) / 100, // MB }, timing: { lastDiscoveryRun: this.lastDiscoveryRun, averageProcessingTime: Math.round(avgProcessingTime * 100) / 100, totalRuns: this.processingTimes.length, }, }; } /** * Record processing time for performance tracking */ recordProcessingTime(processingTime) { this.processingTimes.push(processingTime); // Keep only last 100 measurements to prevent memory bloat if (this.processingTimes.length > 100) { this.processingTimes = this.processingTimes.slice(-100); } } /** * Record discovery run completion */ recordDiscoveryRun() { this.lastDiscoveryRun = Date.now(); } /** * Get performance summary for logging */ getPerformanceSummary() { const metrics = this.getMetrics(); const uptime = Math.round((Date.now() - this.startTime) / 1000); return `Performance Summary (uptime: ${uptime}s): Cache: ${metrics.cache.hitRate}% hit rate (${metrics.cache.hits}/${metrics.cache.hits + metrics.cache.misses}) Discovery: ${metrics.discovery.registered} registered, ${metrics.discovery.pending} pending Memory: ${metrics.memory.heapUsed}MB used / ${metrics.memory.heapTotal}MB total Processing: ${metrics.timing.averageProcessingTime}ms average (${metrics.timing.totalRuns} runs)`; } /** * Start periodic performance reporting */ startPerformanceReporting() { // Report performance every 5 minutes setInterval(() => { const summary = this.getPerformanceSummary(); this.logger.log(summary); // Log warnings for potential performance issues this.checkPerformanceWarnings(); }, 5 * 60 * 1000); } /** * Check for performance warnings and log them */ checkPerformanceWarnings() { const metrics = this.getMetrics(); // Cache hit rate warning if (metrics.cache.hitRate < 50) { this.logger.warn(`Low cache hit rate: ${metrics.cache.hitRate}%. Consider pre-warming cache for frequently accessed services.`); } // Memory usage warning if (metrics.memory.heapUsed > metrics.memory.heapTotal * 0.8) { this.logger.warn(`High memory usage: ${metrics.memory.heapUsed}MB / ${metrics.memory.heapTotal}MB. Consider monitoring for memory leaks.`); } // Processing time warning if (metrics.discovery.processingTime > 1000) { this.logger.warn(`Slow discovery processing: ${metrics.discovery.processingTime}ms average. Consider optimizing service registration.`); } // Retry count warning if (metrics.discovery.retryCount > 10) { this.logger.warn(`High retry count: ${metrics.discovery.retryCount}. Check for service registration issues.`); } } /** * Reset performance metrics (useful for testing) */ resetMetrics() { this.processingTimes = []; this.lastDiscoveryRun = 0; this.logger.log('Performance metrics reset'); } /** * Get performance recommendations based on current metrics */ getRecommendations() { const metrics = this.getMetrics(); const recommendations = []; if (metrics.cache.hitRate < 50) { recommendations.push('Consider pre-warming cache for frequently accessed services'); } if (metrics.discovery.processingTime > 1000) { recommendations.push('Consider optimizing service registration with batching'); } if (metrics.discovery.retryCount > 10) { recommendations.push('Investigate service registration failures and retry logic'); } if (metrics.memory.heapUsed > metrics.memory.heapTotal * 0.8) { recommendations.push('Monitor memory usage and consider implementing memory cleanup'); } if (recommendations.length === 0) { recommendations.push('Performance is within acceptable ranges'); } return recommendations; } }; exports.PerformanceMonitorService = PerformanceMonitorService; exports.PerformanceMonitorService = PerformanceMonitorService = PerformanceMonitorService_1 = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", [event_metadata_explorer_service_1.EventMetadataExplorer, event_discovery_service_1.EventDiscoveryService]) ], PerformanceMonitorService);