Semafy
Semaphore & Mutex implementation for node
Installing
npm install semafy
API
See docs/ for details (or wiki for the latest documentation)
TLDR; This library provides:
-
Semaphore
Acquisition returns a SemaphoreLock. This ensures that:- Only a call that has acquired the semaphore (aka decremented its value) can release it (aka increment its value)
- A call can release the semaphore once at most
-
Mutex
A convenience class for defining a binary Semaphore.new Mutex()
is functionally equivalent tonew Semaphore(1)
. -
RawSemaphore
Similar to a Semaphore but without using SemaphoreLocks, so it does not have the same restrictions. Anything with a reference to the semaphore can:- Increment it via post(), regardless of if the semaphore was first acquired
- Increment it multiple times
- Increment it above the initial value the semaphore was created with
Usage
Semaphore
With Promises
import { Semaphore } from 'semafy';
// Limit calls to 5 per second
const delay = 1000; // ms
const semaphore = new Semaphore(5);
async function rateLimit(callback) {
const lock = await semaphore.wait();
setTimeout(() => lock.unlock(), delay);
callback();
}
With Callbacks
import { Semaphore } from 'semafy';
// Limit calls to 5 per second
const delay = 1000; // ms
const semaphore = new Semaphore(5);
function rateLimit(callback) {
semaphore.wait((error, lock) => {
if (error) {
// Could not acquire semaphore
// Handle error...
return;
}
setTimeout(() => lock.unlock(), delay);
callback();
});
}
With Timeout
import { Semaphore } from 'semafy';
// Limit calls to 5 per second
// Give up after 8 seconds
const delay = 1000; // ms
const timeout = 8000; // ms
const semaphore = new Semaphore(5);
async function rateLimit(callback) {
const lock = await semaphore.waitFor(timeout);
setTimeout(() => lock.unlock(), delay);
callback();
}
or
import { Semaphore } from 'semafy';
// Limit calls to 5 per second
// Give up after 8 seconds
const delay = 1000; // ms
const timeout = 8000; // ms
const semaphore = new Semaphore(5);
function rateLimit(callback) {
semaphore.waitFor(timeout, (error, lock) => {
if (error) {
// Could not acquire semaphore
// Handle error...
return;
}
setTimeout(() => lock.unlock(), delay);
callback();
});
}
tryWait()
import { Semaphore } from 'semafy';
const semaphore = new Semaphore(5);
function nowOrNever(callback) {
const lock = semaphore.tryWait();
if (lock) {
try {
callback();
} finally {
lock.unlock();
}
}
}
Raw Semaphore
With Promises
import { RawSemaphore } from 'semafy';
// Limit calls to 5 per second
const delay = 1000; // ms
const semaphore = new RawSemaphore(5);
async function rateLimit(callback) {
await semaphore.wait();
setTimeout(() => semaphore.post(), delay);
callback();
}
With Callbacks and Timeout
import { RawSemaphore } from 'semafy';
// Limit calls to 5 per second
// Give up after 8 seconds
const delay = 1000; // ms
const timeout = 8000; // ms
const semaphore = new RawSemaphore(5);
function rateLimit(callback) {
semaphore.waitFor(timeout, (error, sem) => {
if (error) {
// Could not acquire semaphore
// Handle error...
return;
}
setTimeout(() => sem.post(), delay);
callback();
});
}
tryWait()
import { RawSemaphore } from 'semafy';
const semaphore = new RawSemaphore(5);
function nowOrNever(callback) {
if (semaphore.tryWait()) {
try {
callback();
} finally {
semaphore.post();
}
}
}
Contribute
There are many ways to contribute:
- Submit bugs and help verify fixes.
- Review source code changes.
- Contribute bug fixes.