Skip to content

Commit

Permalink
Merge pull request #3410 from dmichon-msft/fix-async-concurrency
Browse files Browse the repository at this point in the history
[node-core-library] Fix Async.forEachAsync concurrency
  • Loading branch information
iclanton authored May 10, 2022
2 parents 894e2d7 + 4ba5cca commit 8887475
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/node-core-library",
"comment": "Fix and issue where Async.forEachAsync with an async iterator can overflow the max concurrency",
"type": "patch"
}
],
"packageName": "@rushstack/node-core-library"
}
7 changes: 6 additions & 1 deletion libraries/node-core-library/src/Async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,14 @@ export class Async {

async function queueOperationsAsync(): Promise<void> {
while (operationsInProgress < concurrency && !iteratorIsComplete && !promiseHasResolvedOrRejected) {
// Increment the concurrency while waiting for the iterator.
// This function is reentrant, so this ensures that at most `concurrency` executions are waiting
operationsInProgress++;
const currentIteratorResult: IteratorResult<TEntry> = await iterator.next();
// eslint-disable-next-line require-atomic-updates
iteratorIsComplete = !!currentIteratorResult.done;

if (!iteratorIsComplete) {
operationsInProgress++;
Promise.resolve(callback(currentIteratorResult.value, arrayIndex++))
.then(async () => {
operationsInProgress--;
Expand All @@ -115,6 +117,9 @@ export class Async {
promiseHasResolvedOrRejected = true;
reject(error);
});
} else {
// The iterator is complete and there wasn't a value, so untrack the waiting state.
operationsInProgress--;
}
}

Expand Down

0 comments on commit 8887475

Please sign in to comment.