npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

manticore

v0.2.4

Published

Mythical multi-process worker pool

Downloads

72

Readme

manticore

Build Status NPM version Dependency Status devDependency Status

Mythical multi-process worker pool

Fork node.js multi-core workers and crunch legendary workloads.

The core concept is you got some code in a function that does some heavy work and you want to run it many times with maximum benefit of your multi-core CPU, and without the overhead of re-spawning piles single-use sub-processes.

:warning: Early release :sunglasses:

Why yet another worker module?

The worker modules I found on npm all have their problems: they either lack functionality, use external dependencies or make all kinds of weird assumptions that get in the way.

Instead of trying to wrangle my app to fit those unsatisfactory modules I build Manticore to be simple and effective with the features you need to get big things done at hyperspeed without jumping through crazy hoops.

How to use?

You put your code in a function that accepts a single parameter, then add a bunch of them in a worker module. In this module you register the functions to expose them as tasks.

In your main app you setup the pool for that module and execute the methods via the pool with your data parameter and Manticore will spawn (and despawn) workers as needed and distribute the work and return the result as a Promise.

You can use a function that returns a value synchronously, or go asynchronous and either use the node.js-style callback or return a Promise.

By default each worker works on only one job at a time, but there is an option to allow workers to process multiple jobs simultaneously that allows a extra boost for IO-bound tasks (of course assuming you use async IO).

Return value

The return value of the pool is always a ES6-style Promise so you easily use fancy logic like Promise.all() or Promise.race().

For some next level setups you can leverage Promise-glue helpers from modules like Q, Bluebird etc. To get creative and pass the Promises into more exotic modules like React, Baconjs, Lazy.js, Highland and all the other cool utility modules with Promise support.

Keep in mind the parameter object and return value are serialised so you cannot pass functions or prototype based objects, only simple JSON-like data.

Notes

  • Returns a ES6 Promise.
  • Transfers data between threads using pipes (eg: non-blocking).
  • Data gets serialised so only primitive JSON-like data can be transferred.
  • Makes sure you configure concurrent/paralel to suit your app for best performance

Todo

  • Swap JSON serialisation for something that supports Buffers.
  • Separate settings per function.

Usage

Setup worker

Put the worker methods in their own module where they are registered to Manticore:

var mc = require('manticore');

// directly add named function
function myFunc1(params) {
	return heavyStuff(params);
}
mc.registerTask(myFunc1);

// add anonymous function
mc.registerTask('myFunc2', function(params) {
	return heavyStuff(params);
});

There are different ways to return values:

// does it run syncronous?
function myFunc1(params) {
    return heavyStuff(params);
}

// maybe use the node-style callback?
function myFunc2(params, callback) {
    heavyStuff(params, function(err, result) {
        callback(err, result);
    });
}

// or return a Promise?
function myFunc3(params) {
    return heavyStuff(params).then(function(res) {
        return someMoreWork(res)
    };
}

Register in bulk:

// add named functions as array
mc.registerTasks([
    myFunc1,
    myFunc2,
    myFunc3
]);

// register the methods as an object to redefine the name
// - protip: use the module.exports object
mc.registerTasks({
    myFuncA: myFunc1
    myFuncB: myFunc2
    myFuncC: myFunc3
});

Use the pool

Create a pool in the main app:

var mc = require('manticore');

var pool = mc.createPool({
	modulePath: require.resolve('./worker'),
	concurrent: 4
});

Then run the methods by name, pass a parameter value and get a Promise:

pool.run('myFunc1', myParams).then(function(res) {
    // got results
}, function(err) {
    // oops
});

For convenience get a curried function:

var func1 = pool.curried('myFunc1');

func1(params).then(function(res) {
    // got results
});

Pro-tip: for serious bulk processing use Promise.all() (in Bluebird this is fun with Promise.map() etc).

Promise.all(myArray.map(pool.curried('myFunc1'))).then(function(results) {
    // got all the results
});

That's it! :+1:

Pool options

var pool = mc.createPool({
	// path to the worker module. pro-tip: use require.resolve()
	worker: string;
	
	// maximum amount of worker processes
	// - defaults: require('os').cpus().length
	// tip: when running on many cores leave 1 core free for main process: require('os').cpus().length -1
	concurrent?: number;
	// maximum amount of jobs to pass to each worker
	// set this to a higher value if your jobs are async and IO-bound
	// - default: 1
	paralel?: number;
	// maximum retries if a worker fails
	attempts?: number;

	// worker idle timeout in miliseconds, shuts down workers that are idling
	idleTimeout?: number;
	
	// emit 'status' events, handy for debugging
	emit?: boolean;
	// console.log status events for debugging
	log?: boolean;
});

Development

Manticore is written in TypeScript and compiled with Grunt.

For TypeScript user there is a .d.ts file both in the repo and bundled in the npm package (also exported in package.json).

Build

Install development dependencies in your git checkout:

$ npm install

Build and run tests using grunt:

$ grunt test

See the Gruntfile.js for additional commands.

Contributions

They are welcome but please discuss in the issues before you commit to large changes. If you send a PR make sure you code is idiomatic and linted.

History

  • 0.2.0 - Transfer data over non-blocking pipes, renamed modulePath option to worker.
  • 0.1.0 - First release.

License

Copyright (c) 2014 Bart van der Schoor @ Bartvds

Licensed under the MIT license.