Download superlog/apps/proxy/src/semaphore.ts from smlflg/Experimente: direct link, hf CLI and curl.
- Browser
- Download file 1.85 kB
-
https://huggingface.co/smlflg/Experimente/resolve/main/superlog/apps/proxy/src/semaphore.ts
- Command line
-
hf download hf://smlflg/Experimente/superlog/apps/proxy/src/semaphore.ts
-
curl -L -o semaphore.ts https://huggingface.co/smlflg/Experimente/resolve/main/superlog/apps/proxy/src/semaphore.ts
1.85 kB
| /** | |
| * A counting semaphore used to bound how many ingest requests buffer/stream | |
| * concurrently. Combined with the per-request body cap, this makes the proxy's | |
| * memory footprint a provable constant: | |
| * | |
| * max_memory ≈ permits × max_bytes_held_per_request | |
| * | |
| * Acquisition is FIFO and `await`-based: a request that arrives when all permits | |
| * are taken *waits* for one to free up rather than being rejected. That is the | |
| * deliberate design choice — backpressure (the waiter holds only its socket + | |
| * a pending promise, not a body buffer) instead of shedding valid traffic. The | |
| * body is only read after a permit is held, so waiters cost ~nothing. | |
| * | |
| * A permit count of <= 0 disables the limiter (acquire resolves immediately, | |
| * release is a no-op) — an escape hatch via INGEST_MAX_INFLIGHT_REQUESTS=0. | |
| */ | |
| export class Semaphore { | |
| private readonly limited: boolean; | |
| private available: number; | |
| private readonly waiters: Array<() => void> = []; | |
| constructor(permits: number) { | |
| this.limited = permits > 0; | |
| this.available = this.limited ? permits : 0; | |
| } | |
| acquire(): Promise<void> { | |
| if (!this.limited) return Promise.resolve(); | |
| if (this.available > 0) { | |
| this.available -= 1; | |
| return Promise.resolve(); | |
| } | |
| return new Promise<void>((resolve) => { | |
| this.waiters.push(resolve); | |
| }); | |
| } | |
| release(): void { | |
| if (!this.limited) return; | |
| const next = this.waiters.shift(); | |
| if (next) { | |
| // Hand the permit straight to the next waiter without round-tripping | |
| // through `available`, so a steady stream of releases keeps the queue | |
| // draining in FIFO order. | |
| next(); | |
| return; | |
| } | |
| this.available += 1; | |
| } | |
| get availablePermits(): number { | |
| return this.available; | |
| } | |
| get queueLength(): number { | |
| return this.waiters.length; | |
| } | |
| } | |