Recover desktop startup from stale daemon locks

Refs #1950
Refs #1904
Refs #769
This commit is contained in:
Mohamed Boudra
2026-07-15 15:48:09 +02:00
committed by GitHub
parent 7f011d16c5
commit f06792ae89
6 changed files with 516 additions and 75 deletions
@@ -5,6 +5,7 @@ import {
acquirePidLock,
PidLockError,
releasePidLock,
startPidLockHeartbeat,
updatePidLock,
} from "../src/server/pid-lock.js";
import { resolvePaseoHome } from "../src/server/paseo-home.js";
@@ -17,11 +18,13 @@ process.title = "Paseo Supervisor";
interface DaemonRunnerConfig {
devMode: boolean;
reclaimStalePidLock: boolean;
workerArgs: string[];
}
function parseConfig(argv: string[]): DaemonRunnerConfig {
let devMode = false;
let reclaimStalePidLock = false;
const workerArgs: string[] = [];
for (const arg of argv) {
@@ -29,10 +32,14 @@ function parseConfig(argv: string[]): DaemonRunnerConfig {
devMode = true;
continue;
}
if (arg === "--reclaim-stale-pid-lock") {
reclaimStalePidLock = true;
continue;
}
workerArgs.push(arg);
}
return { devMode, workerArgs };
return { devMode, reclaimStalePidLock, workerArgs };
}
function resolveWorkerEntry(): string {
@@ -109,6 +116,7 @@ async function main(): Promise<void> {
try {
await acquirePidLock(paseoHome, null, {
ownerPid: process.pid,
reclaimStaleDesktopLock: config.reclaimStalePidLock,
});
} catch (error) {
if (error instanceof PidLockError) {
@@ -120,17 +128,29 @@ async function main(): Promise<void> {
}
let lockReleased = false;
let requestSupervisorShutdown: ((reason: string) => void) | null = null;
const stopLockHeartbeat = startPidLockHeartbeat(paseoHome, {
ownerPid: process.pid,
onError: (error) => {
const message = error instanceof Error ? error.message : String(error);
process.stderr.write(`PID lock heartbeat failed: ${message}\n`);
if (error instanceof PidLockError) {
requestSupervisorShutdown?.("pid_lock_ownership_lost");
}
},
});
const releaseLock = async (): Promise<void> => {
if (lockReleased) {
return;
}
lockReleased = true;
stopLockHeartbeat();
await releasePidLock(paseoHome, {
ownerPid: process.pid,
});
};
runSupervisor({
const supervisor = runSupervisor({
name: "DaemonRunner",
startupMessage: "Starting daemon worker (IPC restart and crash restart enabled)",
resolveWorkerEntry: () => workerEntry,
@@ -159,6 +179,7 @@ async function main(): Promise<void> {
},
onSupervisorExit: releaseLock,
});
requestSupervisorShutdown = supervisor.requestShutdown;
}
void main().catch((error) => {