All files / utils ConcurrencyLimit.ts

100% Statements 13/13
100% Branches 4/4
100% Functions 3/3
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40                          476x 476x   476x 64x 45x   19x 19x     64x 64x   64x 64x 19x   45x                
/**
 * Runs async tasks with at most `max` in flight at once (#1817).
 *
 * Header preprocessing starts one C preprocessor process per header, and a
 * large embedded project includes hundreds. Unbounded, they would all start
 * together.
 *
 * A finishing task hands its slot straight to the next waiter rather than
 * releasing it. Releasing first would let a caller arriving in between take the
 * slot too, and the count would briefly exceed `max`.
 */
class ConcurrencyLimit {
  static create(max: number): <T>(task: () => Promise<T>) => Promise<T> {
    let active = 0;
    const waiting: Array<() => void> = [];
 
    return async <T>(task: () => Promise<T>): Promise<T> => {
      if (active < max) {
        active += 1;
      } else {
        await new Promise<void>((resolve) => {
          waiting.push(resolve);
        });
      }
      try {
        return await task();
      } finally {
        const next = waiting.shift();
        if (next) {
          next();
        } else {
          active -= 1;
        }
      }
    };
  }
}
 
export default ConcurrencyLimit;