🎯 Improved cleanup timing - coordinate with complete analysis cycle

- Moved cleanup trigger from analysis phase to complete automation cycle
- Cleanup now runs after trading decision is made (enter/hold/exit)
- Added comprehensive post-cycle cleanup that waits for graceful shutdown
- Enhanced cleanup coordination with analysis cycle completion signals
- Force cleanup after complete cycle to ensure all zombie processes are killed
- Added cleanup triggers for all cycle outcomes (trade executed, no opportunity, error, etc.)
- Improved timing to wait for browser processes to close properly
- Better correlation between analysis completion and process cleanup
This commit is contained in:
mindesbunister
2025-07-19 00:44:27 +02:00
parent 10377810c2
commit cca7303b47
3 changed files with 109 additions and 24 deletions

View File

@@ -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<void> {
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('<27> 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<void> {
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<void> {
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 {

View File

@@ -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<void> {
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
}
}