diff --git a/packages/@aws-cdk/cdk-assets-lib/lib/private/p-limit.ts b/packages/@aws-cdk/cdk-assets-lib/lib/private/p-limit.ts index fb62e18da..a909baf3a 100644 --- a/packages/@aws-cdk/cdk-assets-lib/lib/private/p-limit.ts +++ b/packages/@aws-cdk/cdk-assets-lib/lib/private/p-limit.ts @@ -10,6 +10,9 @@ export function pLimit(concurrency: number): PLimit { let stopped = false; function dispatch() { + if (stopped) { + return; + } if (activeCount < concurrency && queue.length > 0) { const [fac, resolve, reject] = queue.shift()!; activeCount++; @@ -41,6 +44,10 @@ export function pLimit(concurrency: number): PLimit { const ret = (promiseFactory: PromiseFactory) => { return new Promise((resolve, reject) => { + if (stopped) { + reject(new Error('Task has been cancelled')); + return; + } queue.push([promiseFactory, resolve, reject]); dispatch(); }); diff --git a/packages/@aws-cdk/cdk-assets-lib/test/private/p-limit.test.ts b/packages/@aws-cdk/cdk-assets-lib/test/private/p-limit.test.ts index 209e1d691..f4693aaac 100644 --- a/packages/@aws-cdk/cdk-assets-lib/test/private/p-limit.test.ts +++ b/packages/@aws-cdk/cdk-assets-lib/test/private/p-limit.test.ts @@ -43,6 +43,23 @@ test('new jobs arent started after dispose is called', async () => { expect(started).toBeLessThanOrEqual(3); }); +test('no new job is started once dispose is called, even with a free slot', async () => { + const limit = pLimit(1); + + limit.dispose(); + + let ran = false; + await expect( + limit(async () => { + ran = true; + }), + ).rejects.toThrow(/cancelled/); + + // activeCount was 0 and concurrency is 1, so before the fix dispatch() + // would start this job immediately despite dispose() having been called. + expect(ran).toBe(false); +}); + function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); }