diff --git a/src/bot/index.js b/src/bot/index.js index 6522efa7..79d6ef8d 100644 --- a/src/bot/index.js +++ b/src/bot/index.js @@ -6,6 +6,7 @@ import { createServer } from 'http'; import { WebSocketServer } from 'ws'; import fs from 'fs'; import path from 'path'; +import { execSync } from 'child_process'; import { logger } from '../utils/logger.js'; import { checkEnv } from '../utils/env.js'; import { getRTK } from '../utils/rtk.js'; @@ -37,16 +38,33 @@ function acquirePidfile() { if (fs.existsSync(PIDFILE)) { const oldPid = parseInt(fs.readFileSync(PIDFILE, 'utf8').trim()); // Check if old process is still alive - try { process.kill(oldPid, 0); - // Same PID or different process - just log warning, don't kill + try { process.kill(oldPid, 0); + // Old process is still running - kill it to prevent port conflicts if (oldPid !== process.pid) { - logger.warn(`⚠ Another zCode instance (PID ${oldPid}) is running — keeping this instance (PID ${process.pid})`); + logger.warn(`⚠ Another zCode instance (PID ${oldPid}) detected — terminating to prevent port conflict`); + try { + process.kill(oldPid, 'SIGTERM'); + logger.info(` ✓ Sent SIGTERM to PID ${oldPid}`); + // Give it time to shut down gracefully + for (let i = 0; i < 5; i++) { + try { process.kill(oldPid, 0); } + catch { break; } // Process is dead + if (i < 4) { + // Sleep 500ms between checks + execSync('sleep 0.5', { stdio: 'ignore' }); + } + } + } catch (e) { + logger.warn(` Failed to kill old PID ${oldPid}: ${e.message}`); + } } else { logger.info(`✓ Pidfile already acquired by this instance (PID ${process.pid})`); } - // Don't kill - just continue with current process - return; - } catch { /* old PID dead, safe to acquire */ } + // Continue - old process should be dead now + } catch { + // Old PID dead, safe to acquire + logger.info(` Old PID ${oldPid} is no longer running`); + } } fs.writeFileSync(PIDFILE, process.pid.toString()); logger.info(`✓ Pidfile acquired: ${PIDFILE} (PID ${process.pid})`);