From 6feb40e702829639c22aae2ae29d63e9ac5e8508 Mon Sep 17 00:00:00 2001 From: AhmetArif0 <147827411+AhmetArif0@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:12:37 +0300 Subject: [PATCH] fix(desktop): wait for backend exit before reloading on connection-config apply The apply handler sent SIGTERM then fired a 150 ms setTimeout to reload the renderer. If the backend took longer to shut down the port was still bound when startHermes() ran after reload, causing an "address already in use" failure. Capture the process reference before resetHermesConnection() nulls it, then await the actual exit event. A 5 s SIGKILL fallback ensures the wait never hangs if the backend ignores SIGTERM. --- apps/desktop/electron/main.cjs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/desktop/electron/main.cjs b/apps/desktop/electron/main.cjs index 254e4a70b3e..bffe5019cc8 100644 --- a/apps/desktop/electron/main.cjs +++ b/apps/desktop/electron/main.cjs @@ -4076,9 +4076,26 @@ ipcMain.handle('hermes:connection-config:save', async (_event, payload) => { ipcMain.handle('hermes:connection-config:apply', async (_event, payload) => { const config = coerceDesktopConnectionConfig(payload) writeDesktopConnectionConfig(config) - resetHermesConnection() - setTimeout(() => mainWindow?.reload(), 150) + // Capture the reference before resetHermesConnection() nulls hermesProcess, + // so we can wait for actual exit rather than assuming a fixed delay is enough. + const dying = hermesProcess && !hermesProcess.killed ? hermesProcess : null + resetHermesConnection() + + if (dying) { + await new Promise(resolve => { + const timer = setTimeout(() => { + try { dying.kill('SIGKILL') } catch {} + resolve() + }, 5000) + dying.once('exit', () => { + clearTimeout(timer) + resolve() + }) + }) + } + + mainWindow?.reload() return sanitizeDesktopConnectionConfig(config) })