Z ZPI 文档 v0.3.8
介绍页

源码

tests/helpers/scope-guardian.mjs

javascript79 行查看原文
// Independent of the Playwright worker: EOF also arrives after a crash/SIGKILL.
// Only descendants observed under that worker are owned; never kill by name or old PID alone.
import { rm } from "node:fs/promises";
import { createInterface } from "node:readline";
import { processSnapshot as snapshot } from "./process-snapshot.ts";

const root = process.argv[2];
const owner = Number(process.argv[3]);
const owned = new Map();
let stopping = false;
let snapshotPending;
let ownerBorn;
async function collect() {
  const processes = await snapshot();
  let changed = true;
  while (changed) {
    changed = false;
    for (const [pid, info] of processes) {
      if (pid === process.pid || pid === owner || owned.has(pid)) continue;
      const parent = processes.get(info.parent);
      if (
        (info.parent === owner && processes.get(owner)?.born === ownerBorn) ||
        (parent && owned.get(info.parent) === parent.born)
      ) {
        owned.set(pid, info.born);
        changed = true;
      }
    }
  }
  return processes;
}
async function signal(kind) {
  const processes = await collect();
  for (const [pid, born] of [...owned].reverse()) {
    if (processes.get(pid)?.born !== born) continue;
    try {
      process.kill(pid, kind);
    } catch (error) {
      if (error.code !== "ESRCH") throw error;
    }
  }
}
async function finish() {
  if (stopping) return;
  stopping = true;
  clearInterval(timer);
  try {
    await snapshotPending;
    await signal("SIGTERM");
    await new Promise((resolve) => setTimeout(resolve, 300));
    await signal("SIGKILL");
    await rm(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
    process.exit(0);
  } catch (error) {
    console.error("Test scope cleanup failed:", error);
    process.exit(1);
  }
}
const input = createInterface({ input: process.stdin });
input.on("line", (line) => {
  if (line === "close") void finish();
});
input.on("close", () => void finish());
const timer = setInterval(() => {
  if (!snapshotPending)
    snapshotPending = collect()
      .catch((error) => {
        console.error(error);
        process.exitCode = 1;
      })
      .finally(() => {
        snapshotPending = undefined;
      });
}, 100);
ownerBorn = (await snapshot()).get(owner)?.born;
if (!ownerBorn) throw new Error("Test scope owner disappeared");
await collect();
console.log("ready");