UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

275 lines (274 loc) 9.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.memoryMonitor = exports.MemoryMonitor = void 0; /** * Memory usage monitoring and optimization alerts */ const events_1 = require("events"); class MemoryMonitor extends events_1.EventEmitter { constructor() { super(); this.monitoring = false; this.history = []; this.alerts = []; // Thresholds in MB this.WARNING_HEAP = 50; this.CRITICAL_HEAP = 100; this.WARNING_RSS = 150; this.CRITICAL_RSS = 250; this.setupGCHooks(); } static getInstance() { if (!MemoryMonitor.instance) { MemoryMonitor.instance = new MemoryMonitor(); } return MemoryMonitor.instance; } /** * Start memory monitoring */ start(intervalMs = 10000) { if (this.monitoring) return; this.monitoring = true; this.interval = setInterval(() => { this.checkMemory(); }, intervalMs); // Initial check this.checkMemory(); } /** * Stop memory monitoring */ stop() { if (!this.monitoring) return; this.monitoring = false; if (this.interval) { clearInterval(this.interval); this.interval = undefined; } } /** * Get current memory usage */ getCurrentMemory() { const usage = process.memoryUsage(); return { rss: usage.rss / 1024 / 1024, // MB heapTotal: usage.heapTotal / 1024 / 1024, heapUsed: usage.heapUsed / 1024 / 1024, external: usage.external / 1024 / 1024, arrayBuffers: usage.arrayBuffers / 1024 / 1024 }; } /** * Get formatted memory usage string */ getFormattedMemory() { const mem = this.getCurrentMemory(); return `RSS: ${mem.rss.toFixed(1)}MB, ` + `Heap: ${mem.heapUsed.toFixed(1)}/${mem.heapTotal.toFixed(1)}MB, ` + `External: ${mem.external.toFixed(1)}MB, ` + `ArrayBuffers: ${mem.arrayBuffers.toFixed(1)}MB`; } /** * Get memory usage trend */ getMemoryTrend(samples = 10) { if (this.history.length < samples) { return 'stable'; } const recent = this.history.slice(-samples); const first = recent[0].heapUsed; const last = recent[recent.length - 1].heapUsed; const threshold = 2; // MB if (last - first > threshold) { return 'increasing'; } else if (first - last > threshold) { return 'decreasing'; } else { return 'stable'; } } /** * Get memory statistics */ getStats() { const current = this.getCurrentMemory(); if (this.history.length === 0) { return { current, peak: current, average: current, trend: 'stable', alerts: this.alerts.length }; } const peak = this.history.reduce((max, curr) => ({ rss: Math.max(max.rss, curr.rss), heapTotal: Math.max(max.heapTotal, curr.heapTotal), heapUsed: Math.max(max.heapUsed, curr.heapUsed), external: Math.max(max.external, curr.external), arrayBuffers: Math.max(max.arrayBuffers, curr.arrayBuffers) })); const sum = this.history.reduce((acc, curr) => ({ rss: acc.rss + curr.rss, heapTotal: acc.heapTotal + curr.heapTotal, heapUsed: acc.heapUsed + curr.heapUsed, external: acc.external + curr.external, arrayBuffers: acc.arrayBuffers + curr.arrayBuffers })); const count = this.history.length; const average = { rss: sum.rss / count, heapTotal: sum.heapTotal / count, heapUsed: sum.heapUsed / count, external: sum.external / count, arrayBuffers: sum.arrayBuffers / count }; return { current, peak, average, trend: this.getMemoryTrend(), alerts: this.alerts.length }; } /** * Force garbage collection if available */ forceGC() { if (global.gc) { global.gc(); return true; } return false; } /** * Get optimization suggestions */ getOptimizationSuggestions() { const suggestions = []; const current = this.getCurrentMemory(); const trend = this.getMemoryTrend(); if (current.heapUsed > this.WARNING_HEAP) { suggestions.push('Consider reducing object retention or running garbage collection'); } if (current.external > 20) { suggestions.push('High external memory usage detected - check for large buffers'); } if (current.arrayBuffers > 10) { suggestions.push('High ArrayBuffer usage - ensure proper cleanup'); } if (trend === 'increasing') { suggestions.push('Memory usage is trending upward - check for memory leaks'); } if (this.history.length > 5) { const recentLeaks = this.detectMemoryLeaks(); if (recentLeaks) { suggestions.push('Potential memory leak detected in recent activity'); } } if (!global.gc) { suggestions.push('Run with --expose-gc flag to enable manual garbage collection'); } return suggestions; } /** * Check memory and emit alerts if needed */ checkMemory() { const current = this.getCurrentMemory(); // Store in history (keep last 100 samples) this.history.push(current); if (this.history.length > 100) { this.history.shift(); } // Check for alerts this.checkThresholds(current); // Emit memory update event this.emit('memoryUpdate', current); } /** * Check memory thresholds and create alerts */ checkThresholds(current) { const now = Date.now(); // Heap usage alerts if (current.heapUsed > this.CRITICAL_HEAP) { this.createAlert('critical', this.CRITICAL_HEAP, current.heapUsed, now, 'Critical heap usage - consider memory optimization'); } else if (current.heapUsed > this.WARNING_HEAP) { this.createAlert('warning', this.WARNING_HEAP, current.heapUsed, now, 'High heap usage detected'); } // RSS alerts if (current.rss > this.CRITICAL_RSS) { this.createAlert('critical', this.CRITICAL_RSS, current.rss, now, 'Critical RSS usage - system memory pressure'); } else if (current.rss > this.WARNING_RSS) { this.createAlert('warning', this.WARNING_RSS, current.rss, now, 'High RSS usage detected'); } } /** * Create and emit memory alert */ createAlert(type, threshold, current, timestamp, suggestion) { const alert = { type, threshold, current, timestamp, suggestion }; // Don't spam alerts - only emit if last alert was >30s ago const lastAlert = this.alerts[this.alerts.length - 1]; if (!lastAlert || timestamp - lastAlert.timestamp > 30000) { this.alerts.push(alert); this.emit('memoryAlert', alert); // Auto-GC on critical alerts if (type === 'critical' && global.gc) { this.forceGC(); console.warn('Critical memory usage detected, forced garbage collection'); } } } /** * Detect potential memory leaks */ detectMemoryLeaks() { if (this.history.length < 10) return false; const recent = this.history.slice(-10); const older = this.history.slice(-20, -10); if (older.length === 0) return false; const recentAvg = recent.reduce((sum, mem) => sum + mem.heapUsed, 0) / recent.length; const olderAvg = older.reduce((sum, mem) => sum + mem.heapUsed, 0) / older.length; // Consider it a leak if average increased by >10MB return recentAvg - olderAvg > 10; } /** * Setup garbage collection hooks if available */ setupGCHooks() { if (process.versions && process.versions.v8) { try { // Listen for GC events if available process.on('exit', () => { if (this.monitoring) { this.stop(); } }); } catch { // Ignore if not available } } } } exports.MemoryMonitor = MemoryMonitor; // Export singleton instance exports.memoryMonitor = MemoryMonitor.getInstance();