From 7cc006a2ef4cd8a4210a72e7051cbdc15a36a59a Mon Sep 17 00:00:00 2001 From: YappLeCunt <40585717+YappLeCunt@users.noreply.github.com> Date: Sun, 16 Aug 2026 07:04:40 +0800 Subject: [PATCH] fix(desktop): hard-exit a lock-losing second instance before ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app.quit() does not stop a lock-losing instance from reaching whenReady: the before-quit teardown coordinator defers the quit (event.preventDefault + async backend shutdown), and ready fires in that window. The losing instance then runs the full startup whose reapOrphans() SIGTERMs the running instance's live backend (#87295). The lock-loser holds no state and no backend — requestSingleInstanceLock() has already delivered the argv to the primary by the time it returns false — so there is nothing to clean up. app.exit(0) terminates immediately, before ready, so a second launch routes into the running window and never touches backend machinery. --- apps/desktop/electron/main.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/desktop/electron/main.ts b/apps/desktop/electron/main.ts index b7c095ba86..fd72f710d7 100644 --- a/apps/desktop/electron/main.ts +++ b/apps/desktop/electron/main.ts @@ -14105,9 +14105,17 @@ function registerDeepLinkProtocol() { // second-instance argv. Without the lock a second `hermes://` launch spawns a // whole new app instead of routing into the running one. const _gotSingleInstanceLock = app.requestSingleInstanceLock() +const isPrimaryInstance = _gotSingleInstanceLock -if (!_gotSingleInstanceLock) { - app.quit() +if (!isPrimaryInstance) { + // Hard-exit, not app.quit(): the before-quit teardown coordinator defers a + // plain quit (event.preventDefault + async backend shutdown), and in that + // window `ready` still fires — the lock-losing instance then runs the full + // startup (shortcut registration, createWindow → startHermes), whose + // reapOrphans() SIGTERMs the running instance's live backend (#87295). + // app.exit() terminates immediately, before `ready`, so a second launch + // routes into the running window and never touches backend machinery. + app.exit(0) } else { app.on('second-instance', (_event, argv) => { const url = _extractDeepLink(argv)