Skip to content

Semaphore

A synchronization primitive for limiting concurrent usage

1159 bytes
since v12.6.0

Usage

A semaphore is a synchronization primitive that allows a limited number of concurrent operations to proceed.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(2)
const
const permit: SemaphorePermit
permit
= await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
()
const permit: SemaphorePermit
permit
.
SemaphorePermit.release(): void

Releases this permit back to the semaphore, allowing another operation to acquire it.

release
()

When the semaphore’s capacity is reached, subsequent calls to semaphore.acquire() will block until a permit is released.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(1)
const
const permit: SemaphorePermit
permit
= await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
() // Acquires the only permit
// This next acquire call will block until the first permit is released
const
const blockingAcquire: Promise<SemaphorePermit>
blockingAcquire
=
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
()
// ... later ...
const permit: SemaphorePermit
permit
.
SemaphorePermit.release(): void

Releases this permit back to the semaphore, allowing another operation to acquire it.

release
() // Releasing the permit allows blockingAcquire to resolve

You can acquire permits with a specific weight. The semaphore’s capacity is reduced by this weight. If the remaining capacity is less than the requested weight, the acquisition will block.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(4)
// Acquire a permit with weight 2
const
const permit: SemaphorePermit
permit
= await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
({
weight?: number
weight
: 2 })
// Capacity is now 2. Acquiring with weight 1 or 2 is possible.
await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
({
weight?: number
weight
: 1 })
// Acquiring with weight 2 would block now as capacity is only 1.

A permit can only be released once. Subsequent calls to permit.release() on the same permit instance will have no effect.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(1)
const
const permit: SemaphorePermit
permit
= await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
()
const permit: SemaphorePermit
permit
.
SemaphorePermit.release(): void

Releases this permit back to the semaphore, allowing another operation to acquire it.

release
() // Releases the permit
const permit: SemaphorePermit
permit
.
SemaphorePermit.release(): void

Releases this permit back to the semaphore, allowing another operation to acquire it.

release
() // Has no effect

The semaphore constructor requires a maxCapacity of more than 0. Acquiring a permit requires a weight of more than 0 and not exceeding the semaphore’s maxCapacity. Invalid options will result in errors.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
// Invalid constructor
// new Semaphore(0) // Throws Error: maxCapacity must be > 0
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(2)
// Invalid acquire options
// await semaphore.acquire({ weight: 0 }) // Throws Error: weight must be > 0
// await semaphore.acquire({ weight: 3 }) // Throws Error: weight must be ≤ maxCapacity

You can abort a pending acquisition using an AbortController and its signal. If the signal is aborted before the permit is acquired, the acquire promise will reject with an AbortError.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(1)
await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
() // Occupy the only permit
const
const controller: AbortController
controller
= new
var AbortController: new () => AbortController

A controller object that allows you to abort one or more DOM requests as and when desired.

MDN Reference

AbortController
()
const
const acquirePromise: Promise<SemaphorePermit>
acquirePromise
=
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
({
signal?: AbortSignal
signal
:
const controller: AbortController
controller
.
AbortController.signal: AbortSignal

Returns the AbortSignal object associated with this object.

MDN Reference

signal
})
// Abort the acquisition before it can complete
const controller: AbortController
controller
.
AbortController.abort(reason?: any): void (+1 overload)

Invoking this method will set this object's AbortSignal's aborted flag and signal to any observers that the associated activity is to be aborted.

MDN Reference

abort
()
// The acquirePromise will now reject.
await
const acquirePromise: Promise<SemaphorePermit>
acquirePromise
.
Promise<SemaphorePermit>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void | SemaphorePermit>

Attaches a callback for only the rejection of the Promise.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of the callback.

catch
(
error: any
error
=> {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
error: any
error
.
any
message
) // "This operation was aborted"
})

You can reject all pending and future acquisition requests by calling semaphore.reject(). All promises returned by pending and future acquire calls will reject with the provided error.

import {
class Semaphore

Implements a counting semaphore that controls access to a limited resource. Useful for limiting concurrent operations or access to constrained resources.

Semaphore
} from 'radashi'
const
const semaphore: Semaphore
semaphore
= new
new Semaphore(maxCapacity: number): Semaphore

Creates a new semaphore with the specified capacity.

@parammaxCapacity Maximum number of permits that can be issued simultaneously

Semaphore
(1)
await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
() // Occupy the only permit
const
const acquirePromise: Promise<SemaphorePermit>
acquirePromise
=
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
() // This will block
const
const rejectionError: Error
rejectionError
= new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('Operation cancelled')
const semaphore: Semaphore
semaphore
.
Semaphore.reject(error: Error): void

Rejects all pending acquisition requests.

reject
(
const rejectionError: Error
rejectionError
)
// The acquirePromise will now reject with the specified error.
await
const acquirePromise: Promise<SemaphorePermit>
acquirePromise
.
Promise<SemaphorePermit>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void | SemaphorePermit>

Attaches a callback for only the rejection of the Promise.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of the callback.

catch
(
error: any
error
=> {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
error: any
error
.
any
message
) // "Operation cancelled"
})
// Future acquisition requests will also be rejected.
await
const semaphore: Semaphore
semaphore
.
Semaphore.acquire({ signal, weight, }?: SemaphoreAcquireOptions): Promise<SemaphorePermit>

Acquires a permit from this semaphore, waiting if necessary until one becomes available.

@paramoptions.signal - The signal to abort the acquisition

@paramoptions.weight - The weight of the permit to acquire

@returnsA promise that resolves to a permit when one is available

acquire
().
Promise<SemaphorePermit>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void | SemaphorePermit>

Attaches a callback for only the rejection of the Promise.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of the callback.

catch
(
error: any
error
=> {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
error: any
error
.
any
message
) // "Operation cancelled"
})