diff --git a/packages/chord/src/manager.ts b/packages/chord/src/manager.ts index d8146e683..ae185bf75 100644 --- a/packages/chord/src/manager.ts +++ b/packages/chord/src/manager.ts @@ -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"], diff --git a/packages/chord/test/manager.test.ts b/packages/chord/test/manager.test.ts index 4c2fb6aaf..7281ff720 100644 --- a/packages/chord/test/manager.test.ts +++ b/packages/chord/test/manager.test.ts @@ -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();