Async N-permit FIFO semaphore — limit concurrency to a resource pool.
Module semaphore | Source packages/front/fw/src/io/sync/semaphore.js | Deps none | Worker-safe yes
Resolve
const semaphore = runtime.resolve('semaphore');
const s = semaphore.create(3);
// Returns: { acquire, release, tryAcquire, runExclusive, permits, capacity }
API
| Method | Signature | Returns |
|---|---|---|
create |
(n: number) => SemaphoreInstance |
New instance (n ≥ 1, integer) |
s.acquire |
() => Promise<void> |
Waits for a permit |
s.release |
() => void |
Releases a permit |
s.tryAcquire |
() => boolean |
Acquires if permit available (sync) |
s.runExclusive |
(fn: () => Promise<T>) => Promise<T> |
acquire → fn → release |
s.permits |
getter number |
Currently available permits |
s.capacity |
getter number |
Maximum capacity (N) |
Semantics
create(n): throwsError('semaphore: capacity must be an integer >= 1')ifn < 1or non-integer.acquire: decrementspermitsif available (microtask); otherwise FIFO queue.release: incrementspermitsor passes to the next waiter. ThrowsError('semaphore: release exceeds capacity')ifpermits >= capacity.runExclusive: guaranteed try/finally — releases even iffnthrows.
Examples
Pool of 3 simultaneous connections
const semaphore = runtime.resolve('semaphore');
const s = semaphore.create(3);
async function withConnection(task) {
await s.acquire();
try {
return await task();
} finally {
s.release();
}
}
With runExclusive (recommended pattern)
const result = await s.runExclusive(async () => {
return await fetchFromPool();
});
Concurrency control over a batch
const semaphore = runtime.resolve('semaphore');
const s = semaphore.create(5); // max 5 requests in parallel
await Promise.all(items.map(item =>
s.runExclusive(() => processItem(item))
));
Worker Usage
const worker = fw.createWorker(
async function ({ libs }) {
const s = libs.semaphore.create(2);
await Promise.all([
s.runExclusive(async () => { /* task 1 */ }),
s.runExclusive(async () => { /* task 2 */ }),
s.runExclusive(async () => { /* task 3 — will wait */ }),
]);
},
{ dependencies: ['semaphore'] }
);
Notes
- Strict FIFO queue — waiters are served in arrival order.
releasewithout a correspondingacquire→ throws to detect imbalances.- A semaphore with 1 permit is functionally equivalent to a mutex, but prefer
mutexfor clarity of intent.
See also
- mutex — binary lock (1 permit)
- channel — producer/consumer communication
- tokenBucket — token-based rate limiting