Lock File Handling During Install/Uninstall¶
This document describes how lock files (vayu.lock) are handled during installation and uninstallation across all platforms.
Overview¶
The lock file (vayu.lock) prevents multiple instances of the Vayu engine from running simultaneously. It contains the PID of the running engine process and is located at:
- Windows:
%APPDATA%\vayu-client\vayu.lock - macOS:
~/Library/Application Support/vayu-client/vayu.lock - Linux:
~/.config/vayu-client/vayu.lock
The directory is app.getPath("userData"), which Electron derives from the
name in app/package.json (vayu-client) rather than from the product name,
so it is vayu-client on every platform. engineDataDirectory()
(app/electron/sidecar.ts) is the one place that resolves it; anything else
naming a directory is a copy that can drift.
Platform-Specific Handling¶
Windows (NSIS Installer)¶
Installation (installer.nsh):
- Checks if Vayu is running and prompts user to close it
- Kills any orphaned vayu-engine.exe processes
- Removes stale lock files during installation
Uninstallation (installer.nsh):
- Kills running Vayu and engine processes before uninstall
- "Keep my data" removes only the lock file; "Delete everything" removes the whole data directory, and logs a skip rather than deleting anything if that directory is not there
- Lock file path: $APPDATA\${APP_DATA_DIR}\vayu.lock
NSIS cannot read package.json, so the script defines APP_DATA_DIR once and
uses it everywhere rather than spelling a path.
app/electron/installer-nsh-paths.test.ts fails if that define drifts from the
name, if any path bypasses it, or if a path segment anywhere in the file -
comments included - is productName. It is the Windows counterpart to the
Script lint job's check over the shell scripts, which covers ~/.config/ and
cannot see a .nsh file.
Both macros also flip NSIS back to the user's shell context around those paths.
An all-users install leaves NSIS in the machine context, where $APPDATA is not
the roaming profile Electron writes userData to - so a correctly named path
would still miss the real directory in that install mode.
Until #1393 the script named productName for both, so "Delete everything"
ran RMDir /r over $APPDATA\Vayu and removed nothing the app owns - the same
wrong-directory defect the Linux hooks had, and worse, because here it was a
promise about the user's data rather than a no-op.
macOS (DMG)¶
Installation: - No install hooks (DMG doesn't support them) - Lock file cleanup handled automatically in app startup (see below)
Uninstallation: - User manually drags app to Trash - Lock file cleanup handled automatically in app startup on next launch
Linux (.deb Package)¶
Installation:
- No maintainer script of Vayu's. The package's postinst is the one
electron-builder generates; stale locks are reclaimed by app startup (see
below)
Uninstallation:
- app/installer/linux-prerm.sh, wired as fpm's --before-remove in
app/electron-builder.json, kills any running vayu-engine so dpkg does not
replace or remove the binary underneath a live process. It touches no path,
which is why running as root does not break it
- Lock file cleanup handled automatically in app startup
A postinst and a postrm hook used to clean the lock file here. They were
removed (#1356): both looked for $HOME/.config/vayu/vayu.lock, a directory the
app has never written, and dpkg runs maintainer scripts as root, so even the
right directory name would have resolved under /root rather than the
installing user's home. The recovery they attempted - read the PID, verify it
belongs to vayu-engine, remove the file if not - is what startup already does,
against a path it resolves rather than spells, and at every launch rather than
only at install time.
They also cost more than they looked. afterInstall and afterRemove are
passed to fpm as --after-install and --after-remove, which replace
electron-builder's generated maintainer scripts rather than running alongside
them, so every .deb built while those hooks existed shipped the lock cleanup
in place of the /usr/bin/vayu-client alternative, the chrome-sandbox mode
fix, the mime and desktop database updates and the AppArmor profile Ubuntu 24
requires. Removing them restores all of it. Anything a future hook needs to do
belongs in a script that keeps that generated content, not one that supersedes
it.
AppImage: - No install/uninstall hooks - Lock file cleanup handled automatically in app startup
Automatic Cleanup on App Startup¶
The Electron sidecar (app/electron/sidecar.ts) automatically handles stale lock files:
- Checks lock file before starting the engine
- Reads PID from lock file
- Verifies process is still running - cheap first, subprocess second: a
signal-0 probe answers a PID nothing holds, and only a live PID is worth a
tasklist/pscall to verify the name - Removes stale lock if process is dead
- Logs warnings for debugging
This ensures that: - Stale locks from crashes are cleaned up - Reinstalls work correctly - No manual intervention needed
A live engine is adopted only when its version matches this app's (issue
1492). The lock file can point at a PID that is alive and answering /health¶
but was built for a different Vayu release - a crash-then-relaunch across an
upgrade, or two installed builds sharing a data directory. Adopting it
silently would run every request through a sidecar the renderer was not built
against, so EngineSidecar compares the running engine's /health.version
against app.getVersion() before attaching to it: a match adopts as before,
and a mismatch stops the daemon (POST /shutdown, then the same PID kill the
graceful path already falls back to) and starts this build's own instead,
logging both versions. A version that could not be read at all (the probe
answered but the field was missing or malformed) adopts rather than disrupts
a healthy engine on an ambiguous answer.
Manual Cleanup¶
If needed, users can manually remove the lock file:
Windows:
macOS/Linux:
rm ~/.config/vayu-client/vayu.lock
# or on macOS:
rm ~/Library/Application\ Support/vayu-client/vayu.lock
Implementation Details¶
Windows Implementation¶
- Uses
tasklistandtaskkillcommands - NSIS macros:
customInit,customUnInit,customUnInstall - File:
app/installer/installer.nsh
Linux Maintainer Scripts¶
app/installer/linux-prerm.sh: pre-removal, kills a runningvayu-engine- It is the only one Vayu writes. The packaged
.debstill carries apostinstand apostrm, both generated by electron-builder: the/usr/bin/vayu-clientalternative, thechrome-sandboxmode, the mime and desktop databases and the AppArmor profile Ubuntu 24 needs.afterInstallandafterRemovereplace those generated scripts rather than adding to them, which is what made the two removed hooks worse than dead: every.debbuilt while they existed shipped their lock-file cleanup instead of that setup.
Electron Sidecar¶
- Function:
checkLockFile()- checks lock file and verifies PID - Function:
isVayuEngineRunning()- cross-platform process check with process name verification.process.kill(pid, 0)first on every platform (no subprocess, and the stale-lock case ends there), thentasklist/psto verify the name against PID reuse - Method:
adoptIfVersionMatches()- the version gate above, called at both placesstart()finds a healthy engine already on the port - Automatic cleanup in
start()method - File:
app/electron/sidecar.ts
Testing¶
To test lock file handling:
- Start Vayu - lock file should be created
- Kill engine process - lock file should remain
- Restart Vayu - stale lock should be detected and removed
- Reinstall - the first launch after it reclaims any lock left behind
Troubleshooting¶
Issue: Lock file prevents engine from starting after crash
Solution: The app automatically cleans up stale locks on startup. If this doesn't work, manually remove the lock file (see Manual Cleanup above).
Issue: Multiple instances error after uninstall/reinstall
Solution: Startup reclaims a lock whose PID is not a live vayu-engine, so launching the reinstalled app is the fix. If the engine still refuses to start, the PID in the lock file belongs to a live engine - stop it, or remove the lock file manually.