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));
}