feat: implement comprehensive process cleanup system
- 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
This commit is contained in:
126
lib/aggressive-cleanup.ts
Normal file
126
lib/aggressive-cleanup.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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 constructor() {
|
||||
this.startPeriodicCleanup()
|
||||
}
|
||||
|
||||
static getInstance(): AggressiveCleanup {
|
||||
if (!AggressiveCleanup.instance) {
|
||||
AggressiveCleanup.instance = new AggressiveCleanup()
|
||||
}
|
||||
return AggressiveCleanup.instance
|
||||
}
|
||||
|
||||
private startPeriodicCleanup() {
|
||||
// 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)
|
||||
}
|
||||
|
||||
async cleanupOrphanedProcesses(): Promise<void> {
|
||||
if (this.isRunning) return
|
||||
|
||||
this.isRunning = true
|
||||
console.log('🧹 Running aggressive cleanup for orphaned processes...')
|
||||
|
||||
try {
|
||||
// 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
|
||||
Reference in New Issue
Block a user