mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(server): acquire pid lock for unsupervised daemon workers
The direct worker path (non-supervisor) was not writing paseo.pid, so `paseo daemon status` could not detect the running daemon. This caused test 26-daemon-restart-unsupervised to time out in CI waiting for the status to become "running". Acquire the pid lock before daemon creation, update it with the listen address after start, and release on shutdown/error. Supervision detection now requires both PASEO_SUPERVISED=1 and an active IPC channel to avoid misclassification when the env var is inherited. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { loadConfig } from "./config.js";
|
||||
import { resolvePaseoHome } from "./paseo-home.js";
|
||||
import { createRootLogger } from "./logger.js";
|
||||
import { loadPersistedConfig } from "./persisted-config.js";
|
||||
import { PidLockError } from "./pid-lock.js";
|
||||
import { acquirePidLock, PidLockError, releasePidLock, updatePidLock } from "./pid-lock.js";
|
||||
import type { DaemonLifecycleIntent } from "./bootstrap.js";
|
||||
|
||||
type SupervisorLifecycleMessage =
|
||||
@@ -22,6 +22,8 @@ async function main() {
|
||||
let daemon: Awaited<ReturnType<typeof createPaseoDaemon>> | null = null;
|
||||
let shutdownPromise: Promise<number> | null = null;
|
||||
let exitHookInstalled = false;
|
||||
const supervised = process.env.PASEO_SUPERVISED === "1" && typeof process.send === "function";
|
||||
let pidLockAcquired = false;
|
||||
|
||||
try {
|
||||
paseoHome = resolvePaseoHome();
|
||||
@@ -73,6 +75,10 @@ async function main() {
|
||||
return 1;
|
||||
}
|
||||
await daemon.stop();
|
||||
if (pidLockAcquired) {
|
||||
await releasePidLock(paseoHome);
|
||||
pidLockAcquired = false;
|
||||
}
|
||||
clearTimeout(forceExit);
|
||||
logger.info("Server closed");
|
||||
return options?.successExitCode ?? 0;
|
||||
@@ -131,6 +137,11 @@ async function main() {
|
||||
};
|
||||
|
||||
try {
|
||||
if (!supervised) {
|
||||
await acquirePidLock(paseoHome, null);
|
||||
pidLockAcquired = true;
|
||||
}
|
||||
|
||||
daemon = await createPaseoDaemon(
|
||||
{
|
||||
...config,
|
||||
@@ -139,6 +150,10 @@ async function main() {
|
||||
logger,
|
||||
);
|
||||
} catch (err) {
|
||||
if (pidLockAcquired) {
|
||||
await releasePidLock(paseoHome);
|
||||
pidLockAcquired = false;
|
||||
}
|
||||
if (err instanceof PidLockError) {
|
||||
logger.error({ pid: err.existingLock?.pid }, err.message);
|
||||
process.exit(1);
|
||||
@@ -149,7 +164,22 @@ async function main() {
|
||||
|
||||
try {
|
||||
await daemon.start();
|
||||
if (!supervised) {
|
||||
const listenTarget = daemon.getListenTarget();
|
||||
const listen =
|
||||
listenTarget?.type === "tcp"
|
||||
? `${listenTarget.host}:${listenTarget.port}`
|
||||
: listenTarget?.path;
|
||||
if (!listen) {
|
||||
throw new Error("Daemon did not expose a listen target after startup");
|
||||
}
|
||||
await updatePidLock(paseoHome, { listen });
|
||||
}
|
||||
} catch (err) {
|
||||
if (pidLockAcquired) {
|
||||
await releasePidLock(paseoHome);
|
||||
pidLockAcquired = false;
|
||||
}
|
||||
if (err instanceof PidLockError) {
|
||||
logger.error({ pid: err.existingLock?.pid }, err.message);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user