All files / server/services concurrency.ts

93.75% Statements 15/16
100% Branches 0/0
85.71% Functions 6/7
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            56x 56x   47x 49x 49x     56x 55x                 7x 7x 7x   7x 7x   7x      
/** Maps values with at most `concurrency` mapper calls in flight; keeps order. */
export async function mapWithConcurrency<T, R>(
  values: readonly T[],
  concurrency: number,
  mapper: (value: T) => Promise<R>,
): Promise<R[]> {
  const result = new Array<R>(values.length);
  let cursor = 0;
  async function worker(): Promise<void> {
    while (cursor < values.length) {
      const index = cursor++;
      result[index] = await mapper(values[index]);
    }
  }
  await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, worker));
  return result;
}
 
/**
 * Waits for `operation` at most `timeoutMs`. Returns false on timeout; the
 * operation keeps running but no longer blocks the caller.
 */
export async function settleWithin(operation: Promise<unknown>, timeoutMs: number): Promise<boolean> {
  let timer: ReturnType<typeof setTimeout> | undefined;
  const timedOut = new Promise<false>((resolve) => {
    timer = setTimeout(() => resolve(false), timeoutMs);
    timer.unref?.();
  });
  try {
    return await Promise.race([operation.then(() => true, () => true), timedOut]);
  } finally {
    clearTimeout(timer);
  }
}