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

everlast

v0.4.0

Published

Erlang inspired supervisor for Node.js.

Downloads

49

Readme

node-everlast

This is an event driven supervisor for Node.js designed to be used in your code instead of a CLI. It allows you to spawn children processes based on specifications and define restart strategies. It is inspired by Erlang's supervisor.

For example, this would make starting and managing a worker process per core very easy.

Other tools in this area exist, but they can be unstable, are designed to be used from the CLI, or are weak alternatives to runit which solves a different problem.

One major difference between this supervisor and Erlang's is that you can stop a child, though the restart strategy will still kick in. If this is not desirable then you can set the strategy to Never, so it'll never trigger restarts.

Installing

npm install everlast

Using

See ./examples/run.js for a quick code example and ./tests/Supervisor.js for more complicated examples. Plenty of documentation below.

Run npm test to run the unit tests.

Supervisor

Children are defined by their specs. See Child Spec below.

The children are managed internally in an array. When interacting with the supervisor you typically pass it a child index since multiple children can, and likely will, share an id. For example:

var everlast = require('everlast');
var sup = new everlast.Supervisor(); //uses OneForOne(3, 1) by default

sup.on('running', function(ref) {
  console.log('running:', ref);
  sup.stopChild(ref.idx);
});

sup.on('stopping', function(ref) {
  console.log('stopping:', ref);
});

sup.startChild({ id: 'http', path: './server.js' });

See Child Reference below.

Inherits from EventEmitter. Each event callback gets passed two arguments, ref (child reference, schema is promised) and context (contextual information about the event, no schema is promised).

These events are emitted:

  • starting - A child is starting.
  • running - A child is running, it should be considered "up".
  • stopping - A child is stopping, likely due to stopChild().
  • restarting - A child is restarting, likely due to either restartChild() or the restart strategy.
  • stopped - A child is stopped. See the context for whether the restart strategy will attempt to revive the child.
  • down - A child is stopped and won't be restarted due to the strategy's constraints (max time and retries).

General events:

  • error - Your typical Node.js error event. The only arg is a Error. Used when an asynchronous process hits an error and can't return it to you.

All functions return false on success and a new Error on failure. See ./src/Supervisor.js for more detailed per function documentation.

  • startChild(spec) - Starts the child, validating the spec internally.

  • stopChild(idx) - Stops the child, then deletes it with deleteChild().

  • restartChild(idx) - Restarts the child, settings its state to restarting.

  • stopAllChildren(idxIgnores) - Stops all the children from right-to-left, skipping any indexes in the idxIgnores array.

  • deleteChild(idx) - Deletes the child, which must be already stopped.

  • getChild(idx) - Retrieves the current child ref.

  • countChildren() - Returns a count for the children regardless of their statel

  • checkChildSpecs(specs) - Takes an array of child specs and validates them.

  • getRestartStrategy() - Returns the current restart strategy.

Child Spec

This is the structure passed to startChild() to define how the child will behave.

{
  id: string,   //the id, typically something like "web-server"
  path: string, //the path to the server (ex., `process.cwd() + '/bin/run.js'`)
  args: []      //optional, passed to `child_process.spawn()`,
  env: {}       //optional, extends process.env, passed to `child_process.spawn()`
}

Child Reference

This is the structure passed in all child events. The index (idx) can then be used to trigger further actions, such as adding more children of that type.

{
  id: string,   //the same as the child spec you passed
  idx: int,     //the internal index of the child
  pid: int,     //the child's process's PID

  //Internal to Supervisor only (never sent outside):
  args: [],     //from child spec
  env: {},      //from child spec
  process: ChildProcess, //return value from `child_process.spawn()`
  state: int    //array index from CHILD_STATES
}

Restart Strategies

Each strategy tracks how often a child stops in a given time period. It then compares this against your defined maxRestarts and maxTime to decide whether a restart should be triggered.

If a threshold of restarts happens (maxRestarts) within a given time period (maxTime), then the child is not restarted. For example, using OneForOne with maxRestarts=2 and maxTime=1, if your process stops twice in one second it will not be restarted.

The strategies:

  • everlast.restartStrategies.OneForOne - If a child stops, then only that child will be restarted.

  • everlast.restartStrategies.OneForAll - If a child stops, then restart all children including that one.

  • everlast.restartStrategies.RestForOne - If a child stops, then restart it and the children to the right of it in the start up order, iterating from right-to-left (ex., child at idx 3 stops and 5 children are linked, it restarts 5, then 4, then 3).

  • everlast.restartStrategies.Never - Never triggers restarts.

  • everlast.restartStrategies.Base - All strategies inherit from this. Not meant for use in your code.

Child Spawning

Children are spawned with child_process.spawn(). Their stdout and stderr streams are piped to the process's respective stdout and stderr without modification.

If you tell it to, Supervisor will augment the log lines by replacing %s with the child process's id and PID. For example:

//parent.js
var sup = new Supervisor(null, 3, 2, true);
sup.on('running', function(ref) {
  console.log('running with pid', ref.pid);
});
sup.startChild({ id: 'foo', path: './child.js' });

//child.js
console.log('[%s] doing something');

The resulting output would be:

running with pid 123
[foo@123] doing something

TODO

A list of features that will be implemented which you might expect, especially if you've used Erlang's supervisor.

  • Allow children to be another Supervisor, enabling multi-level trees.