- Create /api/batch-analysis endpoint that collects ALL screenshots first - Then sends all screenshots to AI for comprehensive analysis - Fixes issue where individual timeframes were analyzed immediately - Multi-timeframe analysis now provides cross-timeframe consensus - Update AIAnalysisPanel to use batch analysis for multiple timeframes - Maintains backward compatibility with single timeframe analysis
161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
// Aggressive process cleanup utility
|
|
import { exec } from 'child_process'
|
|
import { promisify } from 'util'
|
|
|
|
const execAsync = promisify(exec)
|
|
|
|
class AggressiveCleanup {
|
|
private static instance: AggressiveCleanup
|
|
private cleanupInterval: NodeJS.Timeout | null = null
|
|
private isRunning = false
|
|
private isInitialized = false
|
|
|
|
private constructor() {
|
|
// Don't auto-start - let startup.ts control it
|
|
}
|
|
|
|
static getInstance(): AggressiveCleanup {
|
|
if (!AggressiveCleanup.instance) {
|
|
AggressiveCleanup.instance = new AggressiveCleanup()
|
|
}
|
|
return AggressiveCleanup.instance
|
|
}
|
|
|
|
startPeriodicCleanup() {
|
|
if (this.isInitialized) {
|
|
console.log('🔄 Aggressive cleanup already initialized')
|
|
return
|
|
}
|
|
|
|
this.isInitialized = true
|
|
console.log('🚀 Starting aggressive cleanup system')
|
|
|
|
// In development, disable aggressive cleanup to avoid interfering with analysis
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('🔒 Aggressive cleanup disabled in development mode')
|
|
return
|
|
}
|
|
|
|
// Clean up every 5 minutes
|
|
this.cleanupInterval = setInterval(async () => {
|
|
try {
|
|
await this.cleanupOrphanedProcesses()
|
|
} catch (error) {
|
|
console.error('Error in periodic cleanup:', error)
|
|
}
|
|
}, 5 * 60 * 1000) // 5 minutes
|
|
|
|
// Also run initial cleanup after 30 seconds
|
|
setTimeout(() => {
|
|
this.cleanupOrphanedProcesses().catch(console.error)
|
|
}, 30000)
|
|
|
|
console.log('✅ Aggressive cleanup system started (5 min intervals)')
|
|
}
|
|
|
|
async cleanupOrphanedProcesses(): Promise<void> {
|
|
if (this.isRunning) return
|
|
|
|
this.isRunning = true
|
|
console.log('🧹 Running aggressive cleanup for orphaned processes...')
|
|
|
|
try {
|
|
// Check for active analysis sessions
|
|
try {
|
|
const { progressTracker } = await import('./progress-tracker')
|
|
const activeSessions = progressTracker.getActiveSessions()
|
|
|
|
if (activeSessions.length > 0) {
|
|
console.log(`⚠️ Skipping cleanup - ${activeSessions.length} active analysis sessions: ${activeSessions.join(', ')}`)
|
|
return
|
|
}
|
|
|
|
console.log('✅ No active analysis sessions, proceeding with cleanup')
|
|
} catch (importError) {
|
|
console.error('❌ Error importing progress tracker:', importError)
|
|
console.log('⚠️ Skipping cleanup due to import error')
|
|
return
|
|
}
|
|
|
|
// Find and kill orphaned chromium processes
|
|
const chromiumProcesses = await this.findChromiumProcesses()
|
|
|
|
if (chromiumProcesses.length > 0) {
|
|
console.log(`Found ${chromiumProcesses.length} chromium processes, cleaning up...`)
|
|
|
|
for (const pid of chromiumProcesses) {
|
|
try {
|
|
await execAsync(`kill -9 ${pid}`)
|
|
console.log(`✅ Killed process ${pid}`)
|
|
} catch (error) {
|
|
// Process might already be dead
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up temp directories
|
|
try {
|
|
await execAsync('rm -rf /tmp/puppeteer_dev_chrome_profile-* 2>/dev/null || true')
|
|
console.log('✅ Cleaned up temp directories')
|
|
} catch (error) {
|
|
// Ignore errors
|
|
}
|
|
|
|
// Clean up shared memory
|
|
try {
|
|
await execAsync('rm -rf /dev/shm/.org.chromium.* 2>/dev/null || true')
|
|
console.log('✅ Cleaned up shared memory')
|
|
} catch (error) {
|
|
// Ignore errors
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error in aggressive cleanup:', error)
|
|
} finally {
|
|
this.isRunning = false
|
|
}
|
|
}
|
|
|
|
private async findChromiumProcesses(): Promise<string[]> {
|
|
try {
|
|
const { stdout } = await execAsync('ps aux | grep -E "(chromium|chrome)" | grep -v grep | awk \'{print $2}\'')
|
|
return stdout.trim().split('\n').filter(pid => pid && pid !== '')
|
|
} catch (error) {
|
|
return []
|
|
}
|
|
}
|
|
|
|
async forceCleanup(): Promise<void> {
|
|
console.log('🚨 Force cleanup initiated...')
|
|
|
|
// Stop periodic cleanup
|
|
if (this.cleanupInterval) {
|
|
clearInterval(this.cleanupInterval)
|
|
}
|
|
|
|
// Run aggressive cleanup
|
|
await this.cleanupOrphanedProcesses()
|
|
|
|
// Kill all chromium processes
|
|
try {
|
|
await execAsync('pkill -9 -f "chromium" 2>/dev/null || true')
|
|
await execAsync('pkill -9 -f "chrome" 2>/dev/null || true')
|
|
console.log('✅ Force killed all browser processes')
|
|
} catch (error) {
|
|
console.error('Error in force cleanup:', error)
|
|
}
|
|
}
|
|
|
|
stop(): void {
|
|
if (this.cleanupInterval) {
|
|
clearInterval(this.cleanupInterval)
|
|
this.cleanupInterval = null
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize the aggressive cleanup
|
|
const aggressiveCleanup = AggressiveCleanup.getInstance()
|
|
|
|
export default aggressiveCleanup
|