
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
A semaphore library for nodejs
// Create
const SemLib = require("sem-lib");
const semID = SemLib.semCreate();
// wait for a token
semID.semTake(callback);
// Add a token to the semaphore
SemLib.semGive();
// Exclusive access
const SemLib = require("sem-lib");
const semID = SemLib.semCreate(1, true);
semID.semTake(function() {
// first exclusive access
...
semID.semGive();
});
semID.semTake(function() {
// second exclusive access
...
semID.semGive();
});
// Synchronization
const SemLib = require("sem-lib");
const semID = SemLib.semCreate(3, true);
function AsyncTask1(semID) {
console.log("AsyncTask1");
semID.semGive();
}
function AsyncTask2(semID) {
console.log("AsyncTask2");
semID.semGive();
}
function AsyncTask3(semID) {
console.log("AsyncTask3");
semID.semGive();
}
setTimeout(function() {
AsyncTask1(semID);
}, 200);
setTimeout(function() {
AsyncTask2(semID);
}, 100);
setTimeout(function() {
AsyncTask3(semID);
}, 300);
semID.semTake(3, function(){
//Executed after AsyncTask1, AsyncTask2 and AsyncTask3
console.log("After all tasks");
});
// Limit simultaneous access
// You have multiple downloads to do and you don't want to blow up your memory nor your cpu
const SemLib = require("sem-lib");
// At most 8 simultanenous downloads
const semID = SemLib.semCreate(8, true);
require('fs').readFile('links', function(err, data) {
if (err) {
throw err;
}
const links = data.toString().trim().split(/\r?\n/);
semID.schedule(links, (link, i, next) => {
console.log(`downloading ${ link }`);
download(link, next);
}, () => {
console.log(`downloaded ${ links.length } links`);
});
});
Create a semaphore. See Semaphore#constructor() for more detauls
See the Semaphore Class
Class| Option | Type | Optional | Default | Description |
|---|---|---|---|---|
capacity | Integer | Yes | 1 | Number of available tokens. i.e. how much concurrency |
isFull | Boolean | Yes | false | Create semaphore with all tokens available |
priority | Integer | Yes | 15 | Default take priority. Lower values means higher priority |
sync | Boolean | Yes | false | Run tasks synchronously instead of waiting for the next tick |
Function) : InwaitingShortcut to semTake({onTake: task})
Object) : Inwaiting | falseWait for the Semaphore availability before calling onTake callback.
Returns false if the semaphore has been destroyed.
task()Function to call when all the tokens have been taken.
shouldTakeToken(availableTokens : Integer, missingTokens : Integer, alreadyTakenTokens : Integer, semID : Semaphore) : BooleanIn case you want to allow the waiting task to take tokens only if certains conditions are met.
hasMissingToken(semID : Semaphore)Called when there are not enough token for the task.
| Option | Type | Optional | Default | Description |
|---|---|---|---|---|
priority | Integer | Yes | Semaphore priority | Task priority. Lower values means higher priority |
num | Integer | Yes | 1 | Number of tokens to take |
timeOut | Integer | Yes | undefined | Time to wait until the task is abandoned |
onTimeOut | Function | Yes | undefined | Function to call when waiting has reached timeout |
onCancel | Function | Yes | undefined | Function to call when waiting has been canceled |
unfair | Boolean | Yes | false | Allows to take tokens from waiting tasks with lower priorities |
sync | Boolean | Yes | undefined | Run this task synchronously. If not defined, honor the semaphore sync option |
Integer, overflow: Boolean)Give the number of tokens to the semaphore.
By default, a semaphore cannot receive more tokens than its capacity.
overflow allows temporary capacity overflow.
During the semGive process, getNumTokens() + num will the number of available tokens.
At the end of the semGive process, then number of available tokens will not exceed the semaphore capacity.
Run all waiting tasks
IntegerReturn the number of available tokens
IntegerReturn the maximum of available tokens
Integer)Set the maximum of available tokens
InwaitingRun a collection of tasks, take one token for each task.
Queuing millions of tasks in the semaphore will use a lot of memory.
For that reason, when you have a collection of tasks, prefer using schedule.
It is faster and uses less memory. See benchmark/memory-profile.js for an example.
schedule(collection : Array | Iterable | Object, priority : Integer)
schedule(collection : Array | Iterable | Object, callback : Function)
schedule(collection : Array | Iterable | Object, priority : Integer, callback : Function)
schedule(collection : Array | Iterable | Object, iteratee : Function, callback : Function)
schedule(collection : Array | Iterable | Object, priority : Integer, iteratee : Function, callback : Function)
const semID = semLib.semCreate(3, true); // 3 tokens full
semID.schedule([
next => {
// task 1
next()
},
next => {
// task 2
next()
}
], () => {
// All tasks were run;
});
const semID = semLib.semCreate(3, true); // 3 tokens ful
semID.schedule([
[/* args 1 */],
[/* args 2 */],
], (args, i, next) => {
// process args
next();
}, () => {
// All args were processed;
});
const semID = semLib.semCreate(3, true); // 3 tokens full
semID.schedule({
s1: next => { /* task 1 */; next() },
s2: next => { /* task 2 */; next() },
}, () => {
// All tasks were run;
});
const semID = semLib.semCreate(3, true); // 3 tokens full
semID.schedule({
s1: [ /* args 1 */ ],
s2: [ /* args 2 */ ],
}, (args, key, next) => {
// process args
next();
}, () => {
// All args were processed;
});
Destroy all inwaiting tasks
Parameters
safe: Boolean, optional, default: undefined, if not false, wait for all inwaiting tasks to be performed, else, cancel inwaiting tasks and destroy
onDestroy: Function optional, Called after semaphore destruction
ClassInteger)The task should take more tokens before running
Integer)Change the task priority
Cancel the task
The MIT License (MIT)
Copyright (c) 2014-2019 Stéphane MBAPE (https://smbape.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FAQs
A semaphore library for nodejs
The npm package sem-lib receives a total of 37 weekly downloads. As such, sem-lib popularity was classified as not popular.
We found that sem-lib demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.