mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-07 17:04:42 +00:00
fix(server): make stale lock recovery upgrade-safe
Only heartbeat-capable locks age out by default. Desktop-managed startup may reclaim legacy locks after its reachability probe, while supervisors shut down if heartbeat detects ownership loss.
This commit is contained in:
@@ -110,6 +110,7 @@ async function main(): Promise<void> {
|
||||
try {
|
||||
await acquirePidLock(paseoHome, null, {
|
||||
ownerPid: process.pid,
|
||||
reclaimLegacyDesktopLock: process.env.PASEO_DESKTOP_MANAGED === "1",
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof PidLockError) {
|
||||
@@ -121,8 +122,16 @@ 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) {
|
||||
@@ -135,7 +144,7 @@ async function main(): Promise<void> {
|
||||
});
|
||||
};
|
||||
|
||||
runSupervisor({
|
||||
const supervisor = runSupervisor({
|
||||
name: "DaemonRunner",
|
||||
startupMessage: "Starting daemon worker (IPC restart and crash restart enabled)",
|
||||
resolveWorkerEntry: () => workerEntry,
|
||||
@@ -164,6 +173,7 @@ async function main(): Promise<void> {
|
||||
},
|
||||
onSupervisorExit: releaseLock,
|
||||
});
|
||||
requestSupervisorShutdown = supervisor.requestShutdown;
|
||||
}
|
||||
|
||||
void main().catch((error) => {
|
||||
|
||||
@@ -47,6 +47,10 @@ interface SupervisorOptions {
|
||||
logFile?: SupervisorLogFileOptions;
|
||||
}
|
||||
|
||||
export interface SupervisorController {
|
||||
requestShutdown(reason: string): void;
|
||||
}
|
||||
|
||||
function describeExit(code: number | null, signal: NodeJS.Signals | null): string {
|
||||
return signal ?? (typeof code === "number" ? `code ${code}` : "unknown");
|
||||
}
|
||||
@@ -105,7 +109,7 @@ function createSupervisorLogStream(options: SupervisorLogFileOptions | undefined
|
||||
});
|
||||
}
|
||||
|
||||
export function runSupervisor(options: SupervisorOptions): void {
|
||||
export function runSupervisor(options: SupervisorOptions): SupervisorController {
|
||||
const restartOnCrash = options.restartOnCrash ?? false;
|
||||
const workerArgs = options.workerArgs ?? process.argv.slice(2);
|
||||
const workerEnv = options.workerEnv ?? process.env;
|
||||
@@ -331,4 +335,6 @@ export function runSupervisor(options: SupervisorOptions): void {
|
||||
process.stdout.write(`[${options.name}] ${options.startupMessage}\n`);
|
||||
writeLifecycleLog(options.startupMessage);
|
||||
spawnWorker();
|
||||
|
||||
return { requestShutdown };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user