chore(telemetry): implement universal path normalizer and omni-reaper to prevent preview sprawl

This commit is contained in:
2026-06-09 16:11:31 -07:00
parent 7a9c2575f0
commit 137d5975e1
2 changed files with 39 additions and 22 deletions

View File

@@ -827,31 +827,40 @@ export async function startDevServer(
throw new PortOutOfRangeError(opts.port);
}
// 2. Stop ALL tracked rows for this project on the target port.
// Previous runs may have crashed or exited without being marked
// stopped, causing stale rows to accumulate. We reap them
// unconditionally before starting anything new — the AI's intent
// is "I want THIS command on THIS port", so most-recent-write-wins.
const existingRows = await query<{ id: string; pid: number | null }>(
`SELECT id, pid FROM fs_dev_servers
WHERE project_id = $1 AND port = $2 AND state IN ('starting','running','failed')`,
[opts.projectId, opts.port],
// 2. Stop ALL tracked rows for this project on ALL preview ports.
// Because our socket reaper is infallible, the AI never needs to
// sprawl across multiple ports. We unconditionally reap and stop
// every active preview server for this project before starting a new one
// to keep the dashboard clean and prevent memory leaks.
const existingRows = await query<{
id: string;
pid: number | null;
port: number;
}>(
`SELECT id, pid, port FROM fs_dev_servers
WHERE project_id = $1 AND state IN ('starting','running','failed')`,
[opts.projectId],
);
const killPortNodeCmd =
`node -e '` +
`const fs = require("fs"); ` +
`const port = ${opts.port}; ` +
`const portsToKill = [${existingRows
.map((r) => r.port)
.concat(opts.port)
.join(",")}]; ` +
`try { ` +
`const hexPort = port.toString(16).toUpperCase().padStart(4, "0"); ` +
`const tcp = fs.readFileSync("/proc/net/tcp", "utf8"); ` +
`const inodes = []; ` +
`tcp.split("\\n").forEach(line => { ` +
`const parts = line.trim().split(/\\s+/); ` +
`if (parts.length > 9) { ` +
`const local = parts[1]; ` +
`for (const p of portsToKill) { ` +
`const hexPort = p.toString(16).toUpperCase().padStart(4, "0"); ` +
`if (local.endsWith(":" + hexPort)) { inodes.push(parts[9]); } ` +
`} ` +
`} ` +
`}); ` +
`if (inodes.length > 0) { ` +
`fs.readdirSync("/proc").forEach(file => { ` +
@@ -872,7 +881,7 @@ export async function startDevServer(
`}); ` +
`} ` +
`} catch (e) { ` +
`try { require("child_process").execSync("fuser -k -9 ${opts.port}/tcp 2>/dev/null || true"); } catch (err) {} ` +
`try { require("child_process").execSync("fuser -k -9 " + portsToKill.join(",") + "/tcp 2>/dev/null || true"); } catch (err) {} ` +
`}'`;
for (const row of existingRows) {