fix(desktop): shut down cleanly with workspace terminals (#3268)
Workspace terminal shutdown only signaled an npm wrapper, leaving Electron alive with broken output pipes. Make the signal-handling runner the terminal-owned process and route external Electron termination through the existing quit lifecycle.
This commit is contained in:
@@ -15,3 +15,9 @@ export function createElectronSpawnOptions({ env, colorEnv, expoDevUrl }) {
|
||||
export function resolveChildKillTarget(pid, detached) {
|
||||
return detached ? -pid : pid;
|
||||
}
|
||||
|
||||
export function registerDevRunnerShutdownSignals({ signalSource, stop }) {
|
||||
for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
|
||||
signalSource.on(signal, () => stop("SIGTERM"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { createElectronSpawnOptions, resolveChildKillTarget } from "./dev-runner-config.mjs";
|
||||
import { readFileSync } from "node:fs";
|
||||
import {
|
||||
createElectronSpawnOptions,
|
||||
registerDevRunnerShutdownSignals,
|
||||
resolveChildKillTarget,
|
||||
} from "./dev-runner-config.mjs";
|
||||
|
||||
describe("desktop dev process ownership", () => {
|
||||
test("makes the signal-handling runner the workspace terminal process", () => {
|
||||
const paseoConfig = JSON.parse(
|
||||
readFileSync(new URL("../../../paseo.json", import.meta.url), "utf8"),
|
||||
);
|
||||
const devScript = readFileSync(new URL("./dev.sh", import.meta.url), "utf8");
|
||||
|
||||
expect(paseoConfig.scripts.desktop.command).toContain("exec ./packages/desktop/scripts/dev.sh");
|
||||
expect(devScript).toContain('npm --prefix "$DESKTOP_DIR" run build:main');
|
||||
expect(devScript).toContain('exec node "$SCRIPT_DIR/dev-runner.mjs"');
|
||||
});
|
||||
|
||||
test("keeps Electron in the runner process group", () => {
|
||||
const options = createElectronSpawnOptions({
|
||||
env: { PATH: "/usr/bin" },
|
||||
@@ -23,4 +39,24 @@ describe("desktop dev process ownership", () => {
|
||||
expect(resolveChildKillTarget(42, true)).toBe(-42);
|
||||
expect(resolveChildKillTarget(42, false)).toBe(42);
|
||||
});
|
||||
|
||||
test("stops children when the owning terminal hangs up", () => {
|
||||
const listeners = new Map();
|
||||
const receivedSignals = [];
|
||||
|
||||
registerDevRunnerShutdownSignals({
|
||||
signalSource: {
|
||||
on(signal, listener) {
|
||||
listeners.set(signal, listener);
|
||||
},
|
||||
},
|
||||
stop(signal) {
|
||||
receivedSignals.push(signal);
|
||||
},
|
||||
});
|
||||
|
||||
expect(Array.from(listeners.keys())).toEqual(["SIGHUP", "SIGINT", "SIGTERM"]);
|
||||
listeners.get("SIGHUP")();
|
||||
expect(receivedSignals).toEqual(["SIGTERM"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,11 @@ import path from "node:path";
|
||||
import { execFileSync, spawn } from "node:child_process";
|
||||
import { createRequire } from "node:module";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { createElectronSpawnOptions, resolveChildKillTarget } from "./dev-runner-config.mjs";
|
||||
import {
|
||||
createElectronSpawnOptions,
|
||||
registerDevRunnerShutdownSignals,
|
||||
resolveChildKillTarget,
|
||||
} from "./dev-runner-config.mjs";
|
||||
|
||||
import { resolveDevElectronArgs } from "./dev-runner-args.mjs";
|
||||
|
||||
@@ -159,8 +163,7 @@ function canConnect(port, host) {
|
||||
});
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => stopAll("SIGTERM"));
|
||||
process.on("SIGTERM", () => stopAll("SIGTERM"));
|
||||
registerDevRunnerShutdownSignals({ signalSource: process, stop: stopAll });
|
||||
|
||||
spawnChild("metro", "npx", ["expo", "start", "--port", String(expoPort)], {
|
||||
cwd: appDir,
|
||||
|
||||
@@ -31,7 +31,7 @@ export PASEO_DAEMON_ENDPOINT="$DAEMON_ENDPOINT"
|
||||
|
||||
export PASEO_CORS_ORIGINS="${PASEO_CORS_ORIGINS:-*}"
|
||||
|
||||
npm run build:main
|
||||
npm --prefix "$DESKTOP_DIR" run build:main
|
||||
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
echo " Paseo Desktop Dev"
|
||||
|
||||
Reference in New Issue
Block a user