UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

68 lines (67 loc) • 1.89 kB
//#region src/shared/permit-pool.ts /** * FIFO admission with caller-owned lifetime. Cancellation/deadlines only stop * waiting: an acquired permit stays held until its idempotent release is called. * acquire returns null on cancellation/expiry; tryAcquire returns null when busy. */ function createPermitPool(limit) { let active = 0; const waiters = []; const createRelease = () => { active += 1; let released = false; return () => { if (released) return; released = true; active -= 1; while (waiters.length > 0) { const waiter = waiters.shift(); if (!waiter) break; if (waiter.expired()) { waiter.settle(null); continue; } waiter.settle(createRelease()); break; } }; }; const tryAcquire = () => active < limit ? createRelease() : null; return { get pendingCount() { return waiters.length; }, tryAcquire, async acquire({ signal, deadlineAtMs } = {}) { const expired = () => signal?.aborted === true || deadlineAtMs !== void 0 && Date.now() >= deadlineAtMs; if (expired()) return null; const releasePermit = tryAcquire(); if (releasePermit) return releasePermit; return await new Promise((resolve) => { let settled = false; let timer; const cancel = () => waiter.settle(null); const waiter = { expired, settle: (release) => { if (settled) return; settled = true; clearTimeout(timer); signal?.removeEventListener("abort", cancel); const index = waiters.indexOf(waiter); if (index >= 0) waiters.splice(index, 1); resolve(release); } }; if (deadlineAtMs !== void 0) { timer = setTimeout(cancel, Math.max(1, deadlineAtMs - Date.now())); timer.unref(); } signal?.addEventListener("abort", cancel, { once: true }); waiters.push(waiter); }); } }; } //#endregion export { createPermitPool as t };