devflow-ai
Version:
Enterprise-grade AI agent orchestration with swarm management UI dashboard
655 lines (574 loc) • 20.5 kB
text/typescript
/**
* Memory Monitor and Optimization System
*
* Provides real-time monitoring, analysis, and optimization
* recommendations for the Hive Mind memory subsystem.
*/
import { EventEmitter } from 'events';
import { performance } from 'perf_hooks';
import { Memory } from './Memory.js';
import { DatabaseManager } from './DatabaseManager.js';
interface MemoryAlert {
level: 'info' | 'warning' | 'critical';
type: string;
message: string;
value: number;
threshold: number;
timestamp: Date;
recommendations: string[];
}
interface OptimizationSuggestion {
type: 'cache' | 'database' | 'pool' | 'compression' | 'cleanup';
priority: 'low' | 'medium' | 'high' | 'critical';
title: string;
description: string;
estimatedImpact: string;
implementation: string;
effort: 'minimal' | 'moderate' | 'significant';
}
interface MemoryHealthReport {
overall: {
score: number;
status: 'excellent' | 'good' | 'fair' | 'poor' | 'critical';
summary: string;
};
metrics: {
cacheHitRate: number;
avgQueryTime: number;
memoryUtilization: number;
compressionRatio: number;
poolEfficiency: number;
};
alerts: MemoryAlert[];
suggestions: OptimizationSuggestion[];
trends: {
performance: 'improving' | 'stable' | 'degrading';
memoryUsage: 'increasing' | 'stable' | 'decreasing';
cacheEfficiency: 'improving' | 'stable' | 'degrading';
};
}
export class MemoryMonitor extends EventEmitter {
private memory: Memory;
private db: DatabaseManager;
private isActive = false;
private monitoringTimers: NodeJS.Timeout[] = [];
private historicalData: Map<string, number[]> = new Map();
private alertThresholds = {
cacheHitRate: { warning: 50, critical: 30 },
avgQueryTime: { warning: 100, critical: 500 },
memoryUtilization: { warning: 80, critical: 95 },
poolReuseRate: { warning: 30, critical: 10 },
};
private alerts: MemoryAlert[] = [];
private maxHistorySize = 1000;
constructor(memory: Memory, db: DatabaseManager) {
super();
this.memory = memory;
this.db = db;
}
/**
* Start memory monitoring
*/
async start(): Promise<void> {
if (this.isActive) return;
this.isActive = true;
// Real-time monitoring (every 10 seconds)
const realtimeTimer = setInterval(() => {
this.collectMetrics();
}, 10000);
// Health analysis (every minute)
const healthTimer = setInterval(() => {
this.analyzeHealth();
}, 60000);
// Trend analysis (every 5 minutes)
const trendTimer = setInterval(() => {
this.analyzeTrends();
}, 300000);
// Optimization suggestions (every 15 minutes)
const optimizationTimer = setInterval(() => {
this.generateOptimizationSuggestions();
}, 900000);
// Alert cleanup (every hour)
const cleanupTimer = setInterval(() => {
this.cleanupOldAlerts();
}, 3600000);
this.monitoringTimers.push(
realtimeTimer,
healthTimer,
trendTimer,
optimizationTimer,
cleanupTimer,
);
// Initial baseline collection
await this.establishBaseline();
this.emit('monitoring:started');
}
/**
* Stop memory monitoring
*/
stop(): void {
this.isActive = false;
this.monitoringTimers.forEach((timer) => clearInterval(timer));
this.monitoringTimers.length = 0;
this.emit('monitoring:stopped');
}
/**
* Collect real-time metrics
*/
private async collectMetrics(): Promise<void> {
if (!this.isActive) return;
try {
const startTime = performance.now();
// Get memory analytics
const memoryAnalytics = this.memory.getAdvancedAnalytics();
const dbAnalytics = this.db.getDatabaseAnalytics();
// Extract key metrics
const metrics = {
cacheHitRate: memoryAnalytics.cache.hitRate || 0,
avgQueryTime: dbAnalytics.performance.query_execution?.avg || 0,
memoryUtilization: memoryAnalytics.cache.utilizationPercent || 0,
poolEfficiency: this.calculatePoolEfficiency(memoryAnalytics.pools),
dbFragmentation: dbAnalytics.fragmentation || 0,
activeConnections: 1, // Simplified for now
timestamp: Date.now(),
};
// Store historical data
this.storeHistoricalData(metrics);
// Check for alerts
this.checkAlerts(metrics);
const duration = performance.now() - startTime;
this.emit('metrics:collected', { metrics, duration });
} catch (error) {
this.emit('error', error);
}
}
/**
* Establish performance baseline
*/
private async establishBaseline(): Promise<void> {
const samples = [];
for (let i = 0; i < 10; i++) {
await this.collectMetrics();
await new Promise((resolve) => setTimeout(resolve, 1000));
}
this.emit('baseline:established', { samples: samples.length });
}
/**
* Store historical performance data
*/
private storeHistoricalData(metrics: any): void {
for (const [key, value] of Object.entries(metrics)) {
if (typeof value === 'number') {
if (!this.historicalData.has(key)) {
this.historicalData.set(key, []);
}
const history = this.historicalData.get(key)!;
history.push(value);
// Limit history size
if (history.length > this.maxHistorySize) {
history.shift();
}
}
}
}
/**
* Check metrics against alert thresholds
*/
private checkAlerts(metrics: any): void {
const newAlerts: MemoryAlert[] = [];
// Cache hit rate alerts
const cacheHitRate = metrics.cacheHitRate;
if (cacheHitRate < this.alertThresholds.cacheHitRate.critical) {
newAlerts.push({
level: 'critical',
type: 'cache_performance',
message: `Cache hit rate critically low: ${cacheHitRate.toFixed(1)}%`,
value: cacheHitRate,
threshold: this.alertThresholds.cacheHitRate.critical,
timestamp: new Date(),
recommendations: [
'Increase cache size immediately',
'Review access patterns',
'Consider cache warming strategies',
],
});
} else if (cacheHitRate < this.alertThresholds.cacheHitRate.warning) {
newAlerts.push({
level: 'warning',
type: 'cache_performance',
message: `Cache hit rate below optimal: ${cacheHitRate.toFixed(1)}%`,
value: cacheHitRate,
threshold: this.alertThresholds.cacheHitRate.warning,
timestamp: new Date(),
recommendations: [
'Monitor cache patterns',
'Consider increasing cache size',
'Review cache eviction policy',
],
});
}
// Query performance alerts
const avgQueryTime = metrics.avgQueryTime;
if (avgQueryTime > this.alertThresholds.avgQueryTime.critical) {
newAlerts.push({
level: 'critical',
type: 'query_performance',
message: `Query performance critically slow: ${avgQueryTime.toFixed(1)}ms`,
value: avgQueryTime,
threshold: this.alertThresholds.avgQueryTime.critical,
timestamp: new Date(),
recommendations: [
'Immediate database optimization required',
'Review query plans and indexes',
'Consider query result caching',
],
});
} else if (avgQueryTime > this.alertThresholds.avgQueryTime.warning) {
newAlerts.push({
level: 'warning',
type: 'query_performance',
message: `Query performance degraded: ${avgQueryTime.toFixed(1)}ms`,
value: avgQueryTime,
threshold: this.alertThresholds.avgQueryTime.warning,
timestamp: new Date(),
recommendations: [
'Monitor query performance trends',
'Consider database maintenance',
'Review recent schema changes',
],
});
}
// Memory utilization alerts
const memoryUtilization = metrics.memoryUtilization;
if (memoryUtilization > this.alertThresholds.memoryUtilization.critical) {
newAlerts.push({
level: 'critical',
type: 'memory_utilization',
message: `Memory utilization critical: ${memoryUtilization.toFixed(1)}%`,
value: memoryUtilization,
threshold: this.alertThresholds.memoryUtilization.critical,
timestamp: new Date(),
recommendations: [
'Immediate memory cleanup required',
'Increase memory limits',
'Enable aggressive garbage collection',
],
});
} else if (memoryUtilization > this.alertThresholds.memoryUtilization.warning) {
newAlerts.push({
level: 'warning',
type: 'memory_utilization',
message: `Memory utilization high: ${memoryUtilization.toFixed(1)}%`,
value: memoryUtilization,
threshold: this.alertThresholds.memoryUtilization.warning,
timestamp: new Date(),
recommendations: [
'Monitor memory usage trends',
'Consider memory optimization',
'Review cache sizes',
],
});
}
// Add new alerts and emit events
if (newAlerts.length > 0) {
this.alerts.push(...newAlerts);
newAlerts.forEach((alert) => {
this.emit('alert', alert);
});
}
}
/**
* Analyze overall system health
*/
private async analyzeHealth(): Promise<void> {
const memoryHealth = await this.memory.healthCheck();
const dbHealth = await this.db.healthCheck();
const analytics = this.memory.getAdvancedAnalytics();
const healthReport: MemoryHealthReport = {
overall: {
score: this.calculateOverallScore(memoryHealth, dbHealth, analytics),
status: 'good',
summary: '',
},
metrics: {
cacheHitRate: analytics.cache.hitRate || 0,
avgQueryTime: this.getAverageFromHistory('avgQueryTime'),
memoryUtilization: analytics.cache.utilizationPercent || 0,
compressionRatio: 0.7, // Simplified
poolEfficiency: this.calculatePoolEfficiency(analytics.pools),
},
alerts: this.getActiveAlerts(),
suggestions: this.generateHealthSuggestions(analytics),
trends: this.calculateTrends(),
};
// Determine status
if (healthReport.overall.score >= 90) {
healthReport.overall.status = 'excellent';
} else if (healthReport.overall.score >= 75) {
healthReport.overall.status = 'good';
} else if (healthReport.overall.score >= 60) {
healthReport.overall.status = 'fair';
} else if (healthReport.overall.score >= 40) {
healthReport.overall.status = 'poor';
} else {
healthReport.overall.status = 'critical';
}
// Generate summary
healthReport.overall.summary = this.generateHealthSummary(healthReport);
this.emit('health:analyzed', healthReport);
}
/**
* Generate optimization suggestions
*/
private generateOptimizationSuggestions(): void {
const analytics = this.memory.getAdvancedAnalytics();
const suggestions: OptimizationSuggestion[] = [];
// Cache optimization suggestions
if ((analytics.cache.hitRate || 0) < 70) {
suggestions.push({
type: 'cache',
priority: 'high',
title: 'Optimize Cache Configuration',
description: 'Cache hit rate is below optimal threshold',
estimatedImpact: 'Reduce database queries by 20-40%',
implementation: 'Increase cache size and adjust eviction policy',
effort: 'minimal',
});
}
// Database optimization suggestions
const avgQueryTime = this.getAverageFromHistory('avgQueryTime');
if (avgQueryTime > 50) {
suggestions.push({
type: 'database',
priority: 'medium',
title: 'Database Performance Tuning',
description: 'Query execution times are above optimal range',
estimatedImpact: 'Improve query performance by 30-50%',
implementation: 'Add indexes, optimize queries, run ANALYZE',
effort: 'moderate',
});
}
// Pool optimization suggestions
const poolEfficiency = this.calculatePoolEfficiency(analytics.pools);
if (poolEfficiency < 50) {
suggestions.push({
type: 'pool',
priority: 'low',
title: 'Object Pool Optimization',
description: 'Object pools have low reuse rates',
estimatedImpact: 'Reduce garbage collection pressure',
implementation: 'Increase pool sizes and improve object lifecycle',
effort: 'minimal',
});
}
this.emit('suggestions:generated', suggestions);
}
/**
* Calculate pool efficiency
*/
private calculatePoolEfficiency(pools: any): number {
if (!pools) return 0;
const efficiencies = Object.values(pools).map((pool: any) => pool.reuseRate || 0);
return efficiencies.length > 0
? efficiencies.reduce((a, b) => a + b, 0) / efficiencies.length
: 0;
}
/**
* Get average value from historical data
*/
private getAverageFromHistory(metric: string): number {
const history = this.historicalData.get(metric);
if (!history || history.length === 0) return 0;
return history.reduce((a, b) => a + b, 0) / history.length;
}
/**
* Calculate overall health score
*/
private calculateOverallScore(memoryHealth: any, dbHealth: any, analytics: any): number {
let score = 100;
// Cache performance impact (30%)
const cacheHitRate = analytics.cache.hitRate || 0;
score -= Math.max(0, (70 - cacheHitRate) * 0.3);
// Query performance impact (25%)
const avgQueryTime = this.getAverageFromHistory('avgQueryTime');
if (avgQueryTime > 50) {
score -= Math.min(25, (avgQueryTime - 50) * 0.5);
}
// Memory utilization impact (20%)
const memoryUtil = analytics.cache.utilizationPercent || 0;
if (memoryUtil > 80) {
score -= (memoryUtil - 80) * 0.5;
}
// Active alerts impact (15%)
const criticalAlerts = this.alerts.filter((a) => a.level === 'critical').length;
const warningAlerts = this.alerts.filter((a) => a.level === 'warning').length;
score -= criticalAlerts * 10 + warningAlerts * 5;
// Pool efficiency impact (10%)
const poolEff = this.calculatePoolEfficiency(analytics.pools);
score -= Math.max(0, (50 - poolEff) * 0.2);
return Math.max(0, Math.min(100, score));
}
/**
* Get active alerts (within last hour)
*/
private getActiveAlerts(): MemoryAlert[] {
const oneHourAgo = Date.now() - 3600000;
return this.alerts.filter((alert) => alert.timestamp.getTime() > oneHourAgo);
}
/**
* Generate health-based suggestions
*/
private generateHealthSuggestions(analytics: any): OptimizationSuggestion[] {
const suggestions: OptimizationSuggestion[] = [];
// Add specific suggestions based on current state
if ((analytics.cache.utilizationPercent || 0) > 90) {
suggestions.push({
type: 'cache',
priority: 'critical',
title: 'Immediate Cache Memory Relief',
description: 'Cache memory utilization is critically high',
estimatedImpact: 'Prevent system instability',
implementation: 'Increase cache memory limit or enable aggressive cleanup',
effort: 'minimal',
});
}
return suggestions;
}
/**
* Calculate performance trends
*/
private calculateTrends(): any {
const trends = {
performance: 'stable' as 'improving' | 'stable' | 'degrading',
memoryUsage: 'stable' as 'increasing' | 'stable' | 'decreasing',
cacheEfficiency: 'stable' as 'improving' | 'stable' | 'degrading',
};
// Analyze query time trend
const queryTimes = this.historicalData.get('avgQueryTime') || [];
if (queryTimes.length >= 10) {
const recent = queryTimes.slice(-5);
const older = queryTimes.slice(-10, -5);
const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;
const olderAvg = older.reduce((a, b) => a + b, 0) / older.length;
if (recentAvg < olderAvg * 0.9) {
trends.performance = 'improving';
} else if (recentAvg > olderAvg * 1.1) {
trends.performance = 'degrading';
}
}
// Analyze memory usage trend
const memoryUsage = this.historicalData.get('memoryUtilization') || [];
if (memoryUsage.length >= 10) {
const recent = memoryUsage.slice(-5);
const older = memoryUsage.slice(-10, -5);
const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;
const olderAvg = older.reduce((a, b) => a + b, 0) / older.length;
if (recentAvg > olderAvg * 1.05) {
trends.memoryUsage = 'increasing';
} else if (recentAvg < olderAvg * 0.95) {
trends.memoryUsage = 'decreasing';
}
}
// Analyze cache efficiency trend
const cacheHitRates = this.historicalData.get('cacheHitRate') || [];
if (cacheHitRates.length >= 10) {
const recent = cacheHitRates.slice(-5);
const older = cacheHitRates.slice(-10, -5);
const recentAvg = recent.reduce((a, b) => a + b, 0) / recent.length;
const olderAvg = older.reduce((a, b) => a + b, 0) / older.length;
if (recentAvg > olderAvg * 1.05) {
trends.cacheEfficiency = 'improving';
} else if (recentAvg < olderAvg * 0.95) {
trends.cacheEfficiency = 'degrading';
}
}
return trends;
}
/**
* Analyze trends over time
*/
private analyzeTrends(): void {
const trends = this.calculateTrends();
this.emit('trends:analyzed', trends);
}
/**
* Generate health summary
*/
private generateHealthSummary(report: MemoryHealthReport): string {
const { overall, metrics, alerts } = report;
if (overall.status === 'excellent') {
return 'All memory systems are operating at peak efficiency with optimal performance metrics.';
} else if (overall.status === 'good') {
return 'Memory systems are performing well with minor optimization opportunities.';
} else if (overall.status === 'fair') {
return `Memory performance is acceptable but ${alerts.length} issue(s) need attention.`;
} else if (overall.status === 'poor') {
return `Memory systems require optimization. Cache hit rate: ${metrics.cacheHitRate.toFixed(1)}%, Avg query time: ${metrics.avgQueryTime.toFixed(1)}ms.`;
} else {
return `Critical memory issues detected. Immediate intervention required. ${alerts.filter((a) => a.level === 'critical').length} critical alert(s) active.`;
}
}
/**
* Clean up old alerts
*/
private cleanupOldAlerts(): void {
const cutoff = Date.now() - 86400000; // 24 hours
const initialCount = this.alerts.length;
this.alerts = this.alerts.filter((alert) => alert.timestamp.getTime() > cutoff);
const cleaned = initialCount - this.alerts.length;
if (cleaned > 0) {
this.emit('alerts:cleaned', { cleaned });
}
}
/**
* Get current monitoring status
*/
getStatus() {
return {
isActive: this.isActive,
alertCount: this.alerts.length,
criticalAlerts: this.alerts.filter((a) => a.level === 'critical').length,
warningAlerts: this.alerts.filter((a) => a.level === 'warning').length,
historicalDataPoints: Array.from(this.historicalData.entries()).map(([key, values]) => ({
metric: key,
samples: values.length,
})),
};
}
/**
* Get detailed memory report
*/
async generateDetailedReport(): Promise<MemoryHealthReport> {
const memoryHealth = await this.memory.healthCheck();
const dbHealth = await this.db.healthCheck();
const analytics = this.memory.getAdvancedAnalytics();
return {
overall: {
score: this.calculateOverallScore(memoryHealth, dbHealth, analytics),
status: 'good',
summary: '',
},
metrics: {
cacheHitRate: analytics.cache.hitRate || 0,
avgQueryTime: this.getAverageFromHistory('avgQueryTime'),
memoryUtilization: analytics.cache.utilizationPercent || 0,
compressionRatio: 0.7,
poolEfficiency: this.calculatePoolEfficiency(analytics.pools),
},
alerts: this.getActiveAlerts(),
suggestions: this.generateHealthSuggestions(analytics),
trends: this.calculateTrends(),
};
}
/**
* Export monitoring data for analysis
*/
exportData() {
return {
historicalData: Object.fromEntries(this.historicalData),
alerts: this.alerts,
thresholds: this.alertThresholds,
status: this.getStatus(),
};
}
}