fix(chord): a forked child host no longer inherits its parent's CHORD2_LOCK

forkDriver spread process.env into the child, so a child host that forks its own children (or a test run inside a p2 worker) passed its lock on, and children without a lock of their own failed with "locked".
This commit is contained in:
Mario Zechner 2026-10-13 10:05:19 +00:00
parent 018c87ddcb
commit a4d040d30f
2 changed files with 24 additions and 5 deletions

View file

@ -161,13 +161,14 @@ const LOCK_ENV = "CHORD2_LOCK";
export function forkDriver(options: ForkDriverOptions): Driver {
return {
spawn() {
// A lock this process inherited (e.g. as a child host itself) is not the child's: it gets only its own.
const env: NodeJS.ProcessEnv = { ...process.env };
delete env[LOCK_ENV];
Object.assign(env, options.env);
if (options.lock !== undefined) env[LOCK_ENV] = options.lock;
// Detached: the child leads a process group, so the whole tree can be killed.
const child: ChildProcess = fork(options.entry, [...(options.args ?? [])], {
env: {
...process.env,
...options.env,
...(options.lock === undefined ? {} : { [LOCK_ENV]: options.lock }),
},
env,
execArgv: [...(options.execArgv ?? [])],
detached: true,
stdio: ["ignore", options.onOutput ? "pipe" : "inherit", options.onOutput ? "pipe" : "inherit", "ipc"],

View file

@ -45,6 +45,24 @@ describe("processLock", () => {
});
describe("host manager (real child processes)", () => {
// A child host that forks its own children used to pass its CHORD2_LOCK on, so they failed with "locked".
it("a child without a lock does not inherit the parent's lock", async () => {
const name = `chord2-test-${process.pid}-inherited`;
const release = await processLock(name);
const previous = process.env.CHORD2_LOCK;
process.env.CHORD2_LOCK = name;
const manager = createHostManager({ driver: driver() });
try {
await manager.start();
assert.equal(manager.status, "running");
} finally {
if (previous === undefined) delete process.env.CHORD2_LOCK;
else process.env.CHORD2_LOCK = previous;
await manager.stop();
await release();
}
});
it("starts a child host, links it, stops it gracefully", async () => {
const manager = createHostManager({ driver: driver() });
const instance = await manager.start();