diff --git a/lib/aggressive-cleanup.ts b/lib/aggressive-cleanup.ts index df25354..c7743a9 100644 --- a/lib/aggressive-cleanup.ts +++ b/lib/aggressive-cleanup.ts @@ -246,13 +246,13 @@ class AggressiveCleanup { } } - // New method for on-demand cleanup after analysis + // New method for on-demand cleanup after complete automation cycle async runPostAnalysisCleanup(): Promise { - console.log('๐Ÿงน Post-analysis cleanup triggered...') + console.log('๐Ÿงน Post-cycle cleanup triggered (analysis + decision complete)...') - // Small delay to ensure analysis processes are fully closed - console.log('โณ Waiting 3 seconds for analysis processes to close...') - await new Promise(resolve => setTimeout(resolve, 3000)) + // Wait for all browser processes to fully close + console.log('โณ Waiting 5 seconds for all processes to close gracefully...') + await new Promise(resolve => setTimeout(resolve, 5000)) // Check if there are still active sessions before cleaning try { @@ -260,20 +260,89 @@ class AggressiveCleanup { const activeSessions = progressTracker.getActiveSessions() if (activeSessions.length > 0) { - console.log(`โš ๏ธ Post-analysis cleanup: Still ${activeSessions.length} active sessions - deferring cleanup`) + console.log(`โš ๏ธ Post-cycle cleanup: Still ${activeSessions.length} active sessions detected`) + activeSessions.forEach(session => { + const progress = progressTracker.getProgress(session) + if (progress) { + const activeStep = progress.steps.find(step => step.status === 'active') + const currentStep = activeStep ? activeStep.title : 'Unknown' + console.log(` - ${session}: ${currentStep} (Step ${progress.currentStep}/${progress.totalSteps})`) + } + }) - // Schedule a delayed cleanup in case sessions don't clear properly - setTimeout(() => { - console.log('๐Ÿ• Running delayed post-analysis cleanup...') - this.cleanupOrphanedProcesses() - }, 10000) // 10 seconds later - return + // Force cleanup anyway since cycle is complete + console.log('๏ฟฝ Forcing cleanup - analysis cycle is complete regardless of session status') + + // Clean up the session tracker entries that might be stuck + activeSessions.forEach(session => { + console.log(`๐Ÿงน Force clearing stuck session: ${session}`) + progressTracker.deleteSession(session) + }) + } else { + console.log('โœ… No active sessions detected - proceeding with post-cycle cleanup') } } catch (error) { - console.warn('โš ๏ธ Could not check active sessions for post-analysis cleanup:', error) + console.warn('โš ๏ธ Could not check active sessions for post-cycle cleanup:', error) } + // Always run cleanup after complete automation cycle + console.log('๐Ÿงน Running comprehensive post-cycle cleanup...') await this.cleanupOrphanedProcesses() + + console.log('โœ… Post-cycle cleanup completed - all analysis processes should be cleaned up') + } + + // Signal that an analysis cycle is complete and all processes should be cleaned up + async signalAnalysisCycleComplete(): Promise { + console.log('๐ŸŽฏ Analysis cycle completion signal received') + + // Wait a bit longer to ensure all processes have had time to close + console.log('โณ Waiting 3 seconds for graceful process shutdown...') + await new Promise(resolve => setTimeout(resolve, 3000)) + + // Force cleanup of any remaining processes + console.log('๐Ÿงน Running forced cleanup after analysis cycle completion...') + await this.forceCleanupAfterCycle() + } + + private async forceCleanupAfterCycle(): Promise { + console.log('๐Ÿšจ Force cleanup after analysis cycle - cleaning all browser processes') + + try { + // Find all chromium processes + const chromiumProcesses = await this.findChromiumProcesses() + + if (chromiumProcesses.length > 0) { + console.log(`๐Ÿ” Found ${chromiumProcesses.length} chromium processes to clean after cycle completion`) + + // Force kill all chromium processes after cycle is complete + for (const pid of chromiumProcesses) { + try { + console.log(`๐Ÿ—ก๏ธ Force killing process ${pid} (cycle complete)`) + await execAsync(`kill -9 ${pid}`) + } catch (error) { + // Process might already be dead + console.log(`โ„น๏ธ Process ${pid} may already be terminated`) + } + } + + console.log(`โœ… Forcefully cleaned ${chromiumProcesses.length} processes after cycle completion`) + } else { + console.log('โœ… No chromium processes found - cleanup already complete') + } + + // Clean up temp directories + try { + await execAsync('rm -rf /tmp/puppeteer_dev_chrome_profile-* 2>/dev/null || true') + await execAsync('rm -rf /dev/shm/.org.chromium.* 2>/dev/null || true') + console.log('โœ… Cleaned up temp directories and shared memory') + } catch (error) { + console.warn('โš ๏ธ Could not clean temp directories:', error) + } + + } catch (error) { + console.error('Error in force cleanup after cycle:', error) + } } stop(): void { diff --git a/lib/automation-service-simple.ts b/lib/automation-service-simple.ts index f6be9d1..7fc4b77 100644 --- a/lib/automation-service-simple.ts +++ b/lib/automation-service-simple.ts @@ -162,6 +162,8 @@ export class AutomationService { const todayTrades = await this.getTodayTradeCount(this.config.userId) if (todayTrades >= this.config.maxDailyTrades) { console.log(`๐Ÿ“Š Daily trade limit reached (${todayTrades}/${this.config.maxDailyTrades})`) + // Run cleanup even when trade limit is reached + await this.runPostCycleCleanup('trade_limit_reached') return } @@ -169,6 +171,8 @@ export class AutomationService { const analysisResult = await this.performAnalysis() if (!analysisResult) { console.log('โŒ Analysis failed, skipping cycle') + // Run cleanup when analysis fails + await this.runPostCycleCleanup('analysis_failed') return } @@ -182,16 +186,39 @@ export class AutomationService { const tradeDecision = await this.makeTradeDecision(analysisResult) if (!tradeDecision) { console.log('๐Ÿ“Š No trading opportunity found') + // Run cleanup when no trading opportunity + await this.runPostCycleCleanup('no_opportunity') return } // Step 6: Execute trade await this.executeTrade(tradeDecision) + + // Run cleanup after successful trade execution + await this.runPostCycleCleanup('trade_executed') } catch (error) { console.error('Error in automation cycle:', error) this.stats.errorCount++ this.stats.lastError = error instanceof Error ? error.message : 'Unknown error' + + // Run cleanup on error + await this.runPostCycleCleanup('error') + } + } + + private async runPostCycleCleanup(reason: string): Promise { + console.log(`๐Ÿงน Running post-cycle cleanup (reason: ${reason})`) + + // Small delay to ensure all analysis processes have finished + await new Promise(resolve => setTimeout(resolve, 2000)) + + try { + // Signal that the complete analysis cycle is done + await aggressiveCleanup.signalAnalysisCycleComplete() + console.log(`โœ… Post-cycle cleanup completed for: ${reason}`) + } catch (error) { + console.error('Error in post-cycle cleanup:', error) } } @@ -232,9 +259,6 @@ export class AutomationService { console.log('โŒ No multi-timeframe analysis results') progressTracker.updateStep(sessionId, 'capture', 'error', 'No analysis results captured') progressTracker.deleteSession(sessionId) - - // Run post-analysis cleanup - await aggressiveCleanup.runPostAnalysisCleanup() return null } @@ -248,9 +272,6 @@ export class AutomationService { console.log('โŒ Failed to combine multi-timeframe analysis') progressTracker.updateStep(sessionId, 'analysis', 'error', 'Failed to combine analysis results') progressTracker.deleteSession(sessionId) - - // Run post-analysis cleanup - await aggressiveCleanup.runPostAnalysisCleanup() return null } @@ -265,9 +286,6 @@ export class AutomationService { progressTracker.deleteSession(sessionId) }, 2000) - // Run post-analysis cleanup - await aggressiveCleanup.runPostAnalysisCleanup() - return combinedResult } catch (error) { @@ -277,8 +295,6 @@ export class AutomationService { progressTracker.deleteSession(sessionId) }, 5000) - // Run post-analysis cleanup even on error - await aggressiveCleanup.runPostAnalysisCleanup() return null } } diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 57bbe1d..e8c5a94 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ