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

express-cluster-stability

v3.0.1

Published

Stability and multi-core performance for your Express app, via the built-in stable Node.js cluster API.

Downloads

174

Readme

express-cluster-stability

Stability and multi-core performance for your Express app, via the built-in stable Node.js cluster API.

This module is configurable, and has sane defaults for running your Express app stable and fast.

Star this now, so you remember express-cluster-stability when you need it.

Build Status

Prerequisites

  • Node.js >=13.2.0; install via nvm.

(express-cluster-stability@1 is compatible with Node.js >=4.0.0, if you need that.)

Install

npm install --save express-cluster-stability

Usage

Call this module with a workerFunction. Make sure to do all the work inside the worker function, so the master doesn't waste any time on things the workers will do.

Examples

Minimal noop example.

import express from 'express'
import clusterStability from 'express-cluster-stability'

clusterStability(() => express().listen(8000))

Fully functional example, with simple logging in each worker.

import express from 'express'
import clusterStability from 'express-cluster-stability'

clusterStability(({ log }) => {
  const app = express()
  app.get('/', (req, res) => res.send(`Hello world.`))

  return app.listen(8000, () => {
    log(`App ready at http://localhost:8000/`)
  })
})

API

Main function

The module express-cluster-stability is a function which takes one mandatory argument, and two optional ones:

  • workerFunction - Mandatory. Function which will be run in each worker process. Receives the effective options object as an argument, and SHOULD return a server with a .close() method. If it returns a server with a .close() method, express-cluster-stability can use it to close down even more gracefully if an uncaughtexception occurs in a worker. Instead of the server instance, it may return a Promise which resolves to a server with a .close() method.
  • options - Optional. Object with configuration options to override:
    • logLevel - Minimum log level to process. Default is environment variable EXPRESS_CLUSTER_LOG_LEVEL, or info.
    • numberOfWorkers - How many worker processes to spin up. Default is environment variable EXPRESS_CLUSTER_NUMBER_OF_WORKERS, or the number of CPU cores on the server.
    • handleUncaughtException - Whether to handle uncaughtexception in the workers, disconnect it, spin up a new worker in its place, and close the crashing one as cleanly as possible, killing it after workerKillTimeout ms if needed. Default is environment variable EXPRESS_CLUSTER_HANDLE_UNCAUGHT_EXCEPTION, or true.
    • workerRespawnDelay - How long in ms between respawning each new worker. Default is environment variable EXPRESS_CLUSTER_WORKER_RESPAWN_DELAY, or 1000 (ms).
    • workerKillTimeout - How long in ms after trying to shut down a worker nicely, to kill it. Default is environment variable EXPRESS_CLUSTER_WORKER_KILL_TIMEOUT, or 30000 (ms).
    • logger - Function which takes a level string as argument, and returns a function which logs message and any extra arguments to that level. Default is a function which uses console.log and console.error; see Full config options example below.
  • masterFunction - Optional. Function which will be run only in the master process. Receives the effective options object as an argument. May return a Promise, which will delay forking of worker processes until it resolves.

Worker function

The workerFunction will be called with the effective options used, as one argument. That object will also have a property log, which uses logger to log messages. log is an object with one property (function) for each possible log level. These are:

log.fatal(message, ...rest)
log.error(message, ...rest)
log.warn(message, ...rest)
log.info(message, ...rest)
log.debug(message, ...rest)
log.trace(message, ...rest)

log() itself is also a function, aliased to log.info().

Each log function also has a boolean property which tells you if that specific log level is enabled based on the config option logLevel. It can be useful, when you want to skip processing what to log entirely if the level is not relevant. For example:

if (log.debug.enabled) {
  log.debug(calculateExpensivelyWhatToLog(req, res))
}

Other exports

This module also exports two extra utilities, which are available in all contexts:

  • processName - The string Master, or Worker + the worker id.
  • log - A log function like the one you get in your worker function, but default configured. The configuration incorporates any configuration environment variable. Useful for the master process, or whenever you wish to accept the default logLevel and logger.

Use them for example like this:

import { log, processName } from 'express-cluster-stability'

console.log(`INFO: ${processName}: This is the same as the other line.`)
log('This is the same as the other line.')

Full config options example

All configuration options expanded to their default values.

We also show how to use the cluster module directly to access the worker, and output its id as part of the web app response to a client. The string Worker ${cluster.worker.id} (or Master when applicable) is also available from the exported processName in express-cluster-stability.

logger is a function which takes a level string as argument, and returns a function which logs message and any extra arguments to that level. The default implementation is shown in this example.

import os from 'os'
import cluster from 'cluster'
import express from 'express'
import clusterStability, { processName } from 'express-cluster-stability'

clusterStability(
  ({ log }) => {
    log(`Reporting for duty.`)

    const app = express()
    app.get('/', (req, res) =>
      res.send(`Hello world. This is worker ${cluster.worker.id}.\n`)
    )
    app.get('/crash', () => setTimeout(() => crashOnPurposeAsdasd(), 1))

    const port = process.env.PORT || 8000
    return app.listen(port, () => {
      log(`App ready at http://localhost${port === 80 ? '' : `:${port}`}/`)
    })
  },
  {
    numberOfWorkers: os.cpus().length, //       this is the default
    handleUncaughtException: true, //           this is the default
    workerRespawnDelay: 1000, //                this is the default
    workerKillTimeout: 30000, //                this is the default
    logLevel: 'info', //                        this is the default
    logger: level => (message, ...rest) => {
      // this is the default
      if (['fatal', 'error', 'warn'].includes(level.toLowerCase())) {
        console.error(
          `${level.toUpperCase()}: ${processName}: ${message}`,
          ...rest
        )
      } else {
        console.log(
          `${level.toUpperCase()}: ${processName}: ${message}`,
          ...rest
        )
      }
    },
  },
  ({ log }) => {
    log(`Doing some extra master work, only in the master process...`)
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        log(`...before workers are allowed to start forking.`)
        resolve()
      }, 3000)
    })
  }
)