brainy/dist/utils/cacheAutoConfig.js

261 lines
10 KiB
JavaScript
Raw Normal View History

/**
* Intelligent cache auto-configuration system
* Adapts cache settings based on environment, usage patterns, and storage type
*/
export class CacheAutoConfigurator {
constructor() {
this.stats = {
totalQueries: 0,
repeatQueries: 0,
avgQueryTime: 50,
memoryPressure: 0,
storageType: 'memory',
isDistributed: false,
changeFrequency: 0,
readWriteRatio: 10,
};
this.configHistory = [];
this.lastOptimization = 0;
}
/**
* Auto-detect optimal cache configuration based on current conditions
*/
autoDetectOptimalConfig(storageConfig, currentStats) {
// Update stats with current information
if (currentStats) {
this.stats = { ...this.stats, ...currentStats };
}
// Detect environment characteristics
this.detectEnvironment(storageConfig);
// Generate optimal configuration
const result = this.generateOptimalConfig();
// Store for learning
this.configHistory.push(result);
this.lastOptimization = Date.now();
return result;
}
/**
* Dynamically adjust configuration based on runtime performance
*/
adaptConfiguration(currentConfig, performanceMetrics) {
const reasoning = [];
let needsUpdate = false;
// Check if we should update (don't over-optimize)
if (Date.now() - this.lastOptimization < 60000) {
return null; // Wait at least 1 minute between optimizations
}
// Analyze performance patterns
const adaptations = {};
// Low hit rate → adjust cache size or TTL
if (performanceMetrics.hitRate < 0.3) {
if (performanceMetrics.externalChangesDetected > 5) {
// Too many external changes → shorter TTL
adaptations.maxAge = Math.max(60000, currentConfig.maxAge * 0.7);
reasoning.push('Reduced cache TTL due to frequent external changes');
needsUpdate = true;
}
else {
// Expand cache size for better hit rate
adaptations.maxSize = Math.min(500, (currentConfig.maxSize || 100) * 1.5);
reasoning.push('Increased cache size due to low hit rate');
needsUpdate = true;
}
}
// High hit rate but slow responses → might need cache warming
if (performanceMetrics.hitRate > 0.8 && performanceMetrics.avgResponseTime > 100) {
reasoning.push('High hit rate but slow responses - consider cache warming');
}
// Memory pressure → reduce cache size
if (performanceMetrics.memoryUsage > 100 * 1024 * 1024) { // 100MB
adaptations.maxSize = Math.max(20, (currentConfig.maxSize || 100) * 0.7);
reasoning.push('Reduced cache size due to memory pressure');
needsUpdate = true;
}
// Recent external changes → adaptive TTL
if (performanceMetrics.timeSinceLastChange < 30000) { // 30 seconds
adaptations.maxAge = Math.max(30000, currentConfig.maxAge * 0.8);
reasoning.push('Shortened TTL due to recent external changes');
needsUpdate = true;
}
if (!needsUpdate) {
return null;
}
const newCacheConfig = {
...currentConfig,
...adaptations
};
const newRealtimeConfig = this.calculateRealtimeConfig();
return {
cacheConfig: newCacheConfig,
realtimeConfig: newRealtimeConfig,
reasoning
};
}
/**
* Get recommended configuration for specific use case
*/
getRecommendedConfig(useCase) {
const configs = {
'high-consistency': {
cache: { maxAge: 120000, maxSize: 50 },
realtime: { interval: 15000, enabled: true },
reasoning: ['Optimized for data consistency and real-time updates']
},
'balanced': {
cache: { maxAge: 300000, maxSize: 100 },
realtime: { interval: 30000, enabled: true },
reasoning: ['Balanced performance and consistency']
},
'performance-first': {
cache: { maxAge: 600000, maxSize: 200 },
realtime: { interval: 60000, enabled: true },
reasoning: ['Optimized for maximum cache performance']
}
};
const config = configs[useCase];
return {
cacheConfig: {
enabled: true,
...config.cache
},
realtimeConfig: {
updateIndex: true,
updateStatistics: true,
...config.realtime
},
reasoning: config.reasoning
};
}
/**
* Learn from usage patterns and improve recommendations
*/
learnFromUsage(usageData) {
// Update internal stats for better future recommendations
this.stats.totalQueries += usageData.totalQueries;
this.stats.repeatQueries += usageData.cacheHits;
this.stats.avgQueryTime = (this.stats.avgQueryTime + usageData.responseTime) / 2;
this.stats.changeFrequency = usageData.dataChanges / (usageData.timeWindow / 60000);
// Calculate read/write ratio
const writes = usageData.dataChanges;
const reads = usageData.totalQueries;
this.stats.readWriteRatio = reads > 0 ? reads / Math.max(writes, 1) : 10;
}
detectEnvironment(storageConfig) {
// Detect storage type
if (storageConfig?.s3Storage || storageConfig?.customS3Storage) {
this.stats.storageType = 's3';
this.stats.isDistributed = true;
}
else if (storageConfig?.forceFileSystemStorage) {
this.stats.storageType = 'filesystem';
}
else if (storageConfig?.forceMemoryStorage) {
this.stats.storageType = 'memory';
}
else {
// Auto-detect browser vs Node.js
this.stats.storageType = typeof window !== 'undefined' ? 'opfs' : 'filesystem';
}
// Detect distributed mode indicators
this.stats.isDistributed = this.stats.isDistributed ||
Boolean(storageConfig?.s3Storage || storageConfig?.customS3Storage);
}
generateOptimalConfig() {
const reasoning = [];
// Base configuration
let cacheConfig = {
enabled: true,
maxSize: 100,
maxAge: 300000, // 5 minutes
hitCountWeight: 0.3
};
let realtimeConfig = {
enabled: false,
interval: 60000,
updateIndex: true,
updateStatistics: true
};
// Adjust for storage type
if (this.stats.storageType === 's3' || this.stats.isDistributed) {
cacheConfig.maxAge = 180000; // 3 minutes for distributed
realtimeConfig.enabled = true;
realtimeConfig.interval = 30000; // 30 seconds
reasoning.push('Distributed storage detected - enabled real-time updates');
reasoning.push('Reduced cache TTL for distributed consistency');
}
// Adjust for read/write patterns
if (this.stats.readWriteRatio > 20) {
// Read-heavy workload
cacheConfig.maxSize = Math.min(300, (cacheConfig.maxSize || 100) * 2);
cacheConfig.maxAge = Math.min(900000, (cacheConfig.maxAge || 300000) * 1.5); // Up to 15 minutes
reasoning.push('Read-heavy workload detected - increased cache size and TTL');
}
else if (this.stats.readWriteRatio < 5) {
// Write-heavy workload
cacheConfig.maxSize = Math.max(50, (cacheConfig.maxSize || 100) * 0.7);
cacheConfig.maxAge = Math.max(60000, (cacheConfig.maxAge || 300000) * 0.6);
reasoning.push('Write-heavy workload detected - reduced cache size and TTL');
}
// Adjust for change frequency
if (this.stats.changeFrequency > 10) { // More than 10 changes per minute
realtimeConfig.interval = Math.max(10000, realtimeConfig.interval * 0.5);
cacheConfig.maxAge = Math.max(30000, (cacheConfig.maxAge || 300000) * 0.5);
reasoning.push('High change frequency detected - increased update frequency');
}
// Memory constraints
if (this.detectMemoryConstraints()) {
cacheConfig.maxSize = Math.max(20, (cacheConfig.maxSize || 100) * 0.6);
reasoning.push('Memory constraints detected - reduced cache size');
}
// Performance optimization
if (this.stats.avgQueryTime > 200) {
cacheConfig.maxSize = Math.min(500, (cacheConfig.maxSize || 100) * 1.5);
reasoning.push('Slow queries detected - increased cache size');
}
return {
cacheConfig,
realtimeConfig,
reasoning
};
}
calculateRealtimeConfig() {
return {
enabled: this.stats.isDistributed || this.stats.changeFrequency > 1,
interval: this.stats.isDistributed ? 30000 : 60000,
updateIndex: true,
updateStatistics: true
};
}
detectMemoryConstraints() {
// Simple heuristic for memory constraints
try {
if (typeof performance !== 'undefined' && 'memory' in performance) {
const memInfo = performance.memory;
return memInfo.usedJSHeapSize > memInfo.jsHeapSizeLimit * 0.8;
}
}
catch (e) {
// Ignore errors
}
// Default assumption for constrained environments
return false;
}
/**
* Get human-readable explanation of current configuration
*/
getConfigExplanation(config) {
const lines = [
'🤖 Brainy Auto-Configuration:',
'',
`📊 Cache: ${config.cacheConfig.maxSize} queries, ${config.cacheConfig.maxAge / 1000}s TTL`,
`🔄 Updates: ${config.realtimeConfig.enabled ? `Every ${(config.realtimeConfig.interval || 30000) / 1000}s` : 'Disabled'}`,
'',
'🎯 Optimizations applied:'
];
config.reasoning.forEach(reason => {
lines.push(`${reason}`);
});
return lines.join('\n');
}
}
//# sourceMappingURL=cacheAutoConfig.js.map