- Added aggressive cleanup system that runs every 5 minutes to kill orphaned processes - Enhanced process cleanup with better signal handling and forced cleanup - Added startup initialization system to ensure cleanup is properly loaded - Integrated cleanup system into app layouts for automatic initialization - Added zombie process cleanup and temp directory cleanup - Improved Docker container restart behavior for proper process cleanup - Resolves issue with zombie Chrome processes accumulating
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
// Process cleanup utility for graceful shutdown
|
|
import { enhancedScreenshotService } from './enhanced-screenshot'
|
|
import { tradingViewAutomation } from './tradingview-automation'
|
|
|
|
class ProcessCleanup {
|
|
private static instance: ProcessCleanup
|
|
private isShuttingDown = false
|
|
private aggressiveCleanup: any = null
|
|
|
|
private constructor() {
|
|
// Register cleanup handlers
|
|
process.on('SIGINT', this.handleShutdown.bind(this))
|
|
process.on('SIGTERM', this.handleShutdown.bind(this))
|
|
process.on('SIGQUIT', this.handleShutdown.bind(this))
|
|
process.on('uncaughtException', this.handleError.bind(this))
|
|
process.on('unhandledRejection', this.handleError.bind(this))
|
|
|
|
// Lazy load aggressive cleanup to avoid circular imports
|
|
this.loadAggressiveCleanup()
|
|
}
|
|
|
|
private async loadAggressiveCleanup() {
|
|
try {
|
|
const { default: aggressiveCleanup } = await import('./aggressive-cleanup')
|
|
this.aggressiveCleanup = aggressiveCleanup
|
|
} catch (error) {
|
|
console.error('Failed to load aggressive cleanup:', error)
|
|
}
|
|
}
|
|
|
|
static getInstance(): ProcessCleanup {
|
|
if (!ProcessCleanup.instance) {
|
|
ProcessCleanup.instance = new ProcessCleanup()
|
|
}
|
|
return ProcessCleanup.instance
|
|
}
|
|
|
|
private async handleShutdown(signal: string): Promise<void> {
|
|
if (this.isShuttingDown) {
|
|
console.log('Already shutting down, forcing exit...')
|
|
process.exit(1)
|
|
}
|
|
|
|
this.isShuttingDown = true
|
|
console.log(`\n🛑 Received ${signal}, initiating graceful shutdown...`)
|
|
|
|
try {
|
|
// Use aggressive cleanup first
|
|
if (this.aggressiveCleanup) {
|
|
console.log('🧹 Running aggressive cleanup...')
|
|
await this.aggressiveCleanup.forceCleanup()
|
|
}
|
|
|
|
// Clean up screenshot service
|
|
console.log('🧹 Cleaning up screenshot service...')
|
|
await enhancedScreenshotService.cleanup()
|
|
|
|
// Clean up trading view automation
|
|
console.log('🧹 Cleaning up TradingView automation...')
|
|
await tradingViewAutomation.forceCleanup()
|
|
|
|
console.log('✅ Graceful shutdown completed')
|
|
process.exit(0)
|
|
} catch (error) {
|
|
console.error('❌ Error during shutdown:', error)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
private async handleError(error: Error): Promise<void> {
|
|
console.error('❌ Unhandled error:', error)
|
|
|
|
// Attempt cleanup
|
|
try {
|
|
if (this.aggressiveCleanup) {
|
|
await this.aggressiveCleanup.forceCleanup()
|
|
}
|
|
await enhancedScreenshotService.cleanup()
|
|
await tradingViewAutomation.forceCleanup()
|
|
} catch (cleanupError) {
|
|
console.error('❌ Error during error cleanup:', cleanupError)
|
|
}
|
|
|
|
process.exit(1)
|
|
}
|
|
|
|
// Manual cleanup method
|
|
async cleanup(): Promise<void> {
|
|
await this.handleShutdown('MANUAL')
|
|
}
|
|
}
|
|
|
|
// Initialize the cleanup handler
|
|
const processCleanup = ProcessCleanup.getInstance()
|
|
|
|
export default processCleanup
|