Skip to content

feat(main): requestSingleInstanceLock to prevent PTY loss on AppImage replace - #13

Merged
JeanBaptisteRenard merged 1 commit into
mainfrom
feat/single-instance-lock
May 24, 2026
Merged

JeanBaptisteRenard merged 1 commit into
mainfrom
feat/single-instance-lock

Conversation

@JeanBaptisteRenard

Copy link
Copy Markdown
Collaborator

Problem

On 2026-05-23, replacing the AppImage at ~/Applications/Switchboard.AppImage while Switchboard had active node-pty sessions in the running Electron process killed those sessions. The OS launched the new binary, which initialised a second Electron process. The two instances raced and the running PTYs were orphaned or killed.

Fix

Electron's app.requestSingleInstanceLock() is the standard pattern for this:

  • The first instance acquires the lock and continues to run normally (all PTYs stay alive).
  • Any subsequent launch (e.g. the new AppImage binary after an in-place replace) fails to acquire the lock, calls app.quit() immediately, and exits without touching any PTY or DB.
  • A second-instance listener on the first instance restores and focuses the main window, giving the user visual confirmation the app is still running.

Changes

  • main.js (lines 1601–1673): call app.requestSingleInstanceLock() before app.whenReady(); wrap app.whenReady() and all startup code in the else-branch so it only runs for the true first instance; register app.on('second-instance') to restore/focus mainWindow.

Testing

  • All 45 unit tests pass (node --test)
  • ESLint: 0 errors, 207 warnings (same pre-existing warnings as baseline — none introduced by this change)

… replace

On 2026-05-23, replacing the AppImage while Switchboard had active node-pty
sessions killed those sessions. The OS spawned the new binary which initialised
a second Electron process; the two instances raced and the running PTYs were
orphaned/killed.

Electron's requestSingleInstanceLock() is the standard fix:
- The first instance acquires the lock and continues normally.
- Any subsequent launch (e.g. the new AppImage binary after an in-place replace)
  fails to acquire the lock, calls app.quit() immediately, and exits without
  touching any PTY.
- A 'second-instance' listener on the first instance brings its main window to
  the front, so the user gets visual confirmation the app is still running.

Changes:
- main.js: call app.requestSingleInstanceLock() before app.whenReady()
- Wrap app.whenReady() and all init code in the else-branch so it only runs for
  the true first instance
- Register app.on('second-instance') to restore/focus mainWindow
@JeanBaptisteRenard
JeanBaptisteRenard merged commit 2ff6660 into main May 24, 2026
7 checks passed
@JeanBaptisteRenard
JeanBaptisteRenard deleted the feat/single-instance-lock branch May 24, 2026 01:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant