diff --git a/src/worker-pool.ts b/src/worker-pool.ts --- a/src/worker-pool.ts +++ b/src/worker-pool.ts @@ -89,11 +89,12 @@ inflight.add(done); counts.inc(index); refAll(); - done.then(() => { + const cleanup = () => { inflight.delete(done); counts.dec(index); unrefAll(); - }); + }; + done.then(cleanup, cleanup); } function terminateAll(): void { diff --git a/test/pool-ref.test.ts b/test/pool-ref.test.ts --- a/test/pool-ref.test.ts +++ b/test/pool-ref.test.ts @@ -24,9 +24,16 @@ }); it('refMode lazy pool keeps the process alive while work is in flight', async () => { - // Reuses the same fixture: if workers were unref'd DURING the busy() call, - // the process would exit before printing DONE and stdout would be empty. + // Reuses the same fixture: the exec call rejects (exit 13, unsettled + // top-level await) if workers are unref'd during the call. const { stdout } = await exec(process.execPath, ['--no-warnings', join(fixturesDir, 'ref-mode-main.ts')], { + timeout: 15000, + }); + assert.match(stdout, /DONE done/); + }); + + it("refCount keeps the pool ref'd while any overlapping task is in flight", async () => { + const { stdout } = await exec(process.execPath, ['--no-warnings', join(fixturesDir, 'ref-mode-overlap.ts')], { timeout: 15000, }); assert.match(stdout, /DONE done/); diff --git a/test/fixtures/ref-mode-main.ts b/test/fixtures/ref-mode-main.ts --- a/test/fixtures/ref-mode-main.ts +++ b/test/fixtures/ref-mode-main.ts @@ -4,7 +4,7 @@ // A refMode:'lazy' pool must not keep the process alive once work is done, // even WITHOUT explicit disposal. If the workers stay ref'd, this process // hangs and the test times out. -const run = workers(1, { refMode: 'lazy' } as any); +const run = workers(1, { refMode: 'lazy' }); const result = await run(busy(20)); console.log('DONE ' + result); // No dispose — natural exit is the assertion. diff --git a/test/fixtures/ref-mode-overlap.ts b/test/fixtures/ref-mode-overlap.ts new file mode 100644 --- /dev/null +++ b/test/fixtures/ref-mode-overlap.ts @@ -0,0 +1,12 @@ +import { workers } from 'moroutine'; +import { busy } from './load-balancing.ts'; + +// Overlapping tasks on a lazy pool: if completing the short task unref'd +// the pool while the long one was still in flight, the process would exit +// (code 13) before LONG completes and this would never print. +const run = workers(2, { refMode: 'lazy' }); +const short = run(busy(20)); +const long = run(busy(120)); +await short; +const r = await long; +console.log('DONE ' + r);