fix(server): preserve packaged node runtime for supervised daemon worker

This commit is contained in:
Mohamed Boudra
2026-03-28 09:26:32 +07:00
parent 29876acae5
commit 1b0fe4aa47
2 changed files with 54 additions and 7 deletions

View File

@@ -1,5 +1,6 @@
import { fileURLToPath } from "url";
import { existsSync } from "node:fs";
import path from "node:path";
import { loadConfig } from "../src/server/config.js";
import { acquirePidLock, PidLockError, releasePidLock } from "../src/server/pid-lock.js";
import { resolvePaseoHome } from "../src/server/paseo-home.js";
@@ -55,13 +56,30 @@ function resolveWorkerExecArgv(workerEntry: string): string[] {
return workerEntry.endsWith(".ts") ? ["--import", "tsx"] : [];
}
function resolvePackagedNodeEntrypointRunnerPath(currentScriptPath: string): string | null {
const packageMarker = `${path.sep}node_modules${path.sep}@getpaseo${path.sep}server${path.sep}`;
const markerIndex = currentScriptPath.lastIndexOf(packageMarker);
if (markerIndex === -1) {
return null;
}
const appRoot = currentScriptPath.slice(0, markerIndex);
const runnerPath = path.join(appRoot, "dist", "daemon", "node-entrypoint-runner.js");
return existsSync(runnerPath) ? runnerPath : null;
}
async function main(): Promise<void> {
const config = parseConfig(process.argv.slice(2));
const workerEntry = config.devMode ? resolveDevWorkerEntry() : resolveWorkerEntry();
const workerExecArgv = resolveWorkerExecArgv(workerEntry);
const workerEnv: NodeJS.ProcessEnv = {
...process.env,
PASEO_PID_LOCK_MODE: "external",
};
const packagedNodeEntrypointRunner =
process.env.ELECTRON_RUN_AS_NODE === "1"
? resolvePackagedNodeEntrypointRunnerPath(fileURLToPath(import.meta.url))
: null;
applySherpaLoaderEnv(workerEnv);
@@ -100,7 +118,22 @@ async function main(): Promise<void> {
resolveWorkerEntry: () => workerEntry,
workerArgs: config.workerArgs,
workerEnv,
workerExecArgv: resolveWorkerExecArgv(workerEntry),
workerExecArgv,
resolveWorkerSpawnSpec: packagedNodeEntrypointRunner
? (resolvedWorkerEntry) => ({
command: process.execPath,
args: [
packagedNodeEntrypointRunner,
"node-script",
resolvedWorkerEntry,
...config.workerArgs,
],
env: {
...workerEnv,
ELECTRON_RUN_AS_NODE: "1",
},
})
: undefined,
restartOnCrash: config.devMode,
onSupervisorExit: releaseLock,
});

View File

@@ -1,4 +1,4 @@
import { fork, type ChildProcess } from "child_process";
import { fork, spawn, type ChildProcess } from "child_process";
type WorkerLifecycleMessage =
| {
@@ -16,6 +16,11 @@ type SupervisorOptions = {
workerArgs?: string[];
workerEnv?: NodeJS.ProcessEnv;
workerExecArgv?: string[];
resolveWorkerSpawnSpec?: (workerEntry: string) => {
command: string;
args: string[];
env?: NodeJS.ProcessEnv;
} | null;
restartOnCrash?: boolean;
onSupervisorExit?: () => Promise<void> | void;
};
@@ -47,6 +52,7 @@ export function runSupervisor(options: SupervisorOptions): void {
const workerArgs = options.workerArgs ?? process.argv.slice(2);
const workerEnv = options.workerEnv ?? process.env;
const workerExecArgv = options.workerExecArgv ?? ["--import", "tsx"];
const resolveWorkerSpawnSpec = options.resolveWorkerSpawnSpec;
let child: ChildProcess | null = null;
let restarting = false;
@@ -84,11 +90,19 @@ export function runSupervisor(options: SupervisorOptions): void {
return;
}
child = fork(workerEntry, workerArgs, {
stdio: "inherit",
env: workerEnv,
execArgv: workerExecArgv,
});
const spawnSpec = resolveWorkerSpawnSpec?.(workerEntry) ?? null;
if (spawnSpec) {
child = spawn(spawnSpec.command, spawnSpec.args, {
stdio: ["inherit", "inherit", "inherit", "ipc"],
env: spawnSpec.env ?? workerEnv,
});
} else {
child = fork(workerEntry, workerArgs, {
stdio: "inherit",
env: workerEnv,
execArgv: workerExecArgv,
});
}
child.on("message", (msg: unknown) => {
const lifecycleMessage = parseLifecycleMessage(msg);