UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

229 lines (228 loc) 8.19 kB
import os from 'os'; import logger from '../../../logger.js'; import { getMemoryStats } from '../parser.js'; import { MemoryLeakDetector } from './memoryLeakDetector.js'; import { ResourceTracker } from './resourceTracker.js'; export class ProcessLifecycleManager { options; memoryLeakDetector = null; resourceTracker = null; memoryManager = null; healthCheckTimer = null; gcTimer = null; isInitialized = false; healthStatus = 'healthy'; cpuUsage = { user: 0, system: 0 }; lastCpuUsage = { user: 0, system: 0 }; lastCpuUsageTime = process.hrtime.bigint(); activeJobs = new Set(); healthListeners = []; static DEFAULT_OPTIONS = { maxMemoryPercentage: 0.7, healthCheckInterval: 30 * 1000, degradationThreshold: 0.8, emergencyThreshold: 0.9, autoMonitor: true, gcInterval: 5 * 60 * 1000 }; constructor(options = {}) { this.options = { ...ProcessLifecycleManager.DEFAULT_OPTIONS, ...options }; } async init(memoryManager, resourceTracker) { if (this.isInitialized) { return; } this.memoryLeakDetector = new MemoryLeakDetector({ autoDetect: true, checkInterval: this.options.healthCheckInterval }); await this.memoryLeakDetector.init(); this.memoryManager = memoryManager || null; this.resourceTracker = resourceTracker || new ResourceTracker(); if (this.options.autoMonitor) { this.startHealthMonitoring(); this.startPeriodicGC(); } this.isInitialized = true; logger.info('ProcessLifecycleManager initialized'); } startHealthMonitoring() { if (this.healthCheckTimer) { clearInterval(this.healthCheckTimer); } this.lastCpuUsage = process.cpuUsage(); this.lastCpuUsageTime = process.hrtime.bigint(); this.healthCheckTimer = setInterval(() => { this.checkProcessHealth(); }, this.options.healthCheckInterval); logger.debug(`Process health monitoring started with interval: ${this.options.healthCheckInterval}ms`); } stopHealthMonitoring() { if (this.healthCheckTimer) { clearInterval(this.healthCheckTimer); this.healthCheckTimer = null; } logger.debug('Process health monitoring stopped'); } startPeriodicGC() { if (this.gcTimer) { clearInterval(this.gcTimer); } this.gcTimer = setInterval(() => { this.runGarbageCollection(); }, this.options.gcInterval); logger.debug(`Periodic garbage collection started with interval: ${this.options.gcInterval}ms`); } stopPeriodicGC() { if (this.gcTimer) { clearInterval(this.gcTimer); this.gcTimer = null; } logger.debug('Periodic garbage collection stopped'); } checkProcessHealth() { const memoryStats = getMemoryStats(); const memoryUsagePercentage = memoryStats.memoryUsagePercentage; const currentCpuUsage = process.cpuUsage(); const currentTime = process.hrtime.bigint(); const elapsedTime = Number(currentTime - this.lastCpuUsageTime) / 1e9; const userUsage = (currentCpuUsage.user - this.lastCpuUsage.user) / 1000 / elapsedTime; const systemUsage = (currentCpuUsage.system - this.lastCpuUsage.system) / 1000 / elapsedTime; const cpuUsagePercentage = (userUsage + systemUsage) / (os.cpus().length * 100); this.lastCpuUsage = currentCpuUsage; this.lastCpuUsageTime = currentTime; const memoryLeakResult = this.memoryLeakDetector?.analyzeMemoryTrend(); const memoryLeakDetected = memoryLeakResult?.leakDetected || false; let newStatus = 'healthy'; if (memoryUsagePercentage > this.options.emergencyThreshold) { newStatus = 'critical'; this.handleCriticalMemory(); } else if (memoryUsagePercentage > this.options.degradationThreshold || memoryLeakDetected) { newStatus = 'degraded'; this.handleDegradedMemory(); } else if (this.healthStatus === 'critical' || this.healthStatus === 'degraded') { newStatus = 'recovering'; } const previousStatus = this.healthStatus; this.healthStatus = newStatus; if (previousStatus !== newStatus) { logger.info(`Process health status changed from ${previousStatus} to ${newStatus}`); } const healthInfo = { status: newStatus, memoryUsagePercentage, cpuUsagePercentage, memoryLeakDetected, timestamp: Date.now(), memoryStats, activeJobs: this.activeJobs.size }; this.notifyHealthListeners(healthInfo); return healthInfo; } handleDegradedMemory() { logger.warn('Memory usage is degraded, applying graceful degradation measures'); this.runGarbageCollection(); if (this.memoryManager) { this.memoryManager.pruneCaches(); } } handleCriticalMemory() { logger.error('Memory usage is critical, applying emergency measures'); this.runGarbageCollection(); if (this.memoryManager) { this.memoryManager.pruneCaches(); } if (this.memoryLeakDetector) { this.memoryLeakDetector.takeHeapSnapshot() .then(snapshotPath => { logger.info(`Took emergency heap snapshot: ${snapshotPath}`); }) .catch(error => { logger.error(`Failed to take emergency heap snapshot: ${error}`); }); } } runGarbageCollection() { logger.info('Running garbage collection'); if (this.memoryManager) { this.memoryManager.runGarbageCollection(); } else { if (typeof global !== 'undefined' && global.gc) { try { logger.debug('Calling global.gc() to suggest garbage collection'); global.gc(); } catch (error) { logger.warn(`Failed to suggest garbage collection: ${error}`); } } else { logger.debug('global.gc not available. Run Node.js with --expose-gc to enable manual GC suggestions'); } } } registerJob(jobId) { this.activeJobs.add(jobId); if (this.resourceTracker) { this.resourceTracker.trackJob(jobId); } logger.debug(`Registered job: ${jobId}`); } async unregisterJob(jobId) { this.activeJobs.delete(jobId); if (this.resourceTracker) { await this.resourceTracker.cleanupJob(jobId); } logger.debug(`Unregistered job: ${jobId}`); } getActiveJobCount() { return this.activeJobs.size; } getActiveJobIds() { return Array.from(this.activeJobs); } addHealthListener(listener) { this.healthListeners.push(listener); } removeHealthListener(listener) { const index = this.healthListeners.indexOf(listener); if (index !== -1) { this.healthListeners.splice(index, 1); } } notifyHealthListeners(health) { for (const listener of this.healthListeners) { try { listener(health); } catch (error) { logger.warn(`Error in health listener: ${error}`); } } } getHealthStatus() { return this.healthStatus; } getMemoryLeakDetector() { return this.memoryLeakDetector; } getResourceTracker() { return this.resourceTracker; } cleanup() { this.stopHealthMonitoring(); this.stopPeriodicGC(); if (this.memoryLeakDetector) { this.memoryLeakDetector.cleanup(); } this.healthListeners = []; logger.info('Process lifecycle manager cleaned up'); } }