UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

46 lines (45 loc) 1.48 kB
import { AsyncLocalStorage } from "node:async_hooks"; import pMap from "p-map"; //#region src/utils/run-with-concurrency.ts /** Runs async tasks with bounded concurrency while preserving result indexes. */ async function runTasksWithConcurrency(params) { const { tasks, limit, onTaskError, throwOnError = false } = params; const errorMode = params.errorMode ?? "continue"; if (tasks.length === 0) return { results: [], firstError: void 0, hasError: false }; const resolvedLimit = Number.isFinite(limit) ? Math.max(1, Math.min(Math.floor(limit), tasks.length)) : tasks.length; const results = Array.from({ length: tasks.length }); let firstError = void 0; let hasError = false; return new Promise((resolve, reject) => { const runOne = async (task, index) => { if (errorMode === "stop" && hasError) return; try { results[index] = await task(); } catch (error) { if (!hasError) { firstError = error; hasError = true; } let rejectionError = error; try { onTaskError?.(error, index); } catch (callbackError) { rejectionError = callbackError; } if (throwOnError) reject(rejectionError); } }; const mapper = AsyncLocalStorage.bind((task, index) => Promise.resolve().then(() => runOne(task, index))); pMap(tasks.slice(), mapper, { concurrency: resolvedLimit }).then(() => resolve({ results, firstError, hasError }), reject); }); } //#endregion export { runTasksWithConcurrency as t };