Download src/hooks/query/concurrency-limiter.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 1.7 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/hooks/query/concurrency-limiter.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/hooks/query/concurrency-limiter.ts
-
curl -L -o concurrency-limiter.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/hooks/query/concurrency-limiter.ts
1.7 kB
| /** | |
| * A FIFO promise semaphore: at most `limit` wrapped tasks run at once; the | |
| * rest wait in arrival order. Wrap a queryFn's work in `run` to bound how many | |
| * of a query family's requests are in flight simultaneously. | |
| */ | |
| export class ConcurrencyLimiter { | |
| private active = 0; | |
| private readonly queue: Array<() => void> = []; | |
| constructor(private readonly limit: number) {} | |
| async run<T>(task: () => Promise<T>, signal?: AbortSignal): Promise<T> { | |
| await this.acquire(); | |
| try { | |
| // A query cancelled while queued (e.g. its last observer unmounted) | |
| // frees its slot without ever hitting the network. | |
| if (signal?.aborted) { | |
| throw signal.reason ?? new DOMException("Aborted", "AbortError"); | |
| } | |
| return await task(); | |
| } finally { | |
| this.release(); | |
| } | |
| } | |
| private acquire(): Promise<void> { | |
| if (this.active < this.limit) { | |
| this.active += 1; | |
| return Promise.resolve(); | |
| } | |
| return new Promise((resolve) => { | |
| this.queue.push(resolve); | |
| }); | |
| } | |
| private release(): void { | |
| const next = this.queue.shift(); | |
| if (next) { | |
| // The waiter inherits the released slot directly, so `active` stays put. | |
| next(); | |
| } else { | |
| this.active -= 1; | |
| } | |
| } | |
| } | |
| /** | |
| * Shared by every per-automation runs query: the dashboard and home page each | |
| * fan out one GET .../runs request per automation, which can exhaust the | |
| * automation service's DB connection pool (~15 connections) and stall every | |
| * request for the pool's 30s acquisition timeout. Three in flight keeps the | |
| * surfaces responsive without saturating the pool. | |
| */ | |
| export const automationRunRequestsLimiter = new ConcurrencyLimiter(3); | |