The pm2 npm package is a nice tool to
launch and manage multiple apps, including "clustered" versions of apps.
"Clustered" versions of app instances - aka exec_mode: "cluster" - will use
the cluster module to launch your app
instances.

In order to have N|Solid configure your applications correctly, you should
provide the NSOLID_COMMAND, NSOLID_APPNAME, and any other required
environment variables in the pm2 config json file under the env attribute.
N|Solid should be able to use this information to have your managed
applications appear in the N|Solid Console and nsolid-cli.

For the examples below, we have created 4 applications requiring app.js and starting a process:
app-1.js, app-2.js,app-3.js, app-4.js; they all do the same thing but have different "names".
There are two pm2 JSON files to launch the apps in cluster mode - 3 instances
of each app will be created. Those files are pm2-12.json and pm2-34.json.
The first launches app-1 and app-2, the second launches app-3 and
app-4.

app-1.js:

require("./app").start("app-1")

app-2.js:

require("./app").start("app-2")

app-3.js:

app-4.js:

require("./app").start("app-1")
require("./app").start("app-3")

app-4.js:

require("./app").start("app-4")

app.js:

"use strict"

module.exports.start = start

const http = require("http")
const cluster = require("cluster")

const ID = cluster.isMaster ? "master" : `worker-${cluster.worker.id}`
const PORT = process.env.PORT || 0

function start(name) {
  log(`NSOLID_COMMAND: ${process.env.NSOLID_COMMAND}`)
  log(`NSOLID_APPNAME: ${process.env.NSOLID_APPNAME}`)

  const server = http.createServer(requestHandler)
  server.listen(PORT, listenHandler)

  function requestHandler (req, res) {
    log(`${req.method} ${req.url}`)
    res.end("not much here")
    setImmediate(burnCPU)
  }

  function listenHandler () {
    const port = server.address().port
    log(`listening at http://localhost:${port}`)
  }

  function log (message) {
    const date = new Date().toISOString()
    console.log(`${name}-${ID}: ${date}: ${message}`)
  }
}

function burnCPU () {
  const count = 100000
  const numbers = []

  for (let i=0; i<=count; i++) {
    numbers.push(Math.random())
  }

  numbers.sort()
}

pm2-12.json:

{ "apps": [
  {
    "name":         "app-1",
    "script":       "app-1.js",
    "instances":    3,
    "merge_logs":   true,
    "env": {
        "NSOLID_COMMAND": "localhost:9001",
        "NSOLID_APPNAME": "app-1",
        "NODE_ENV": "production",
        "PORT":     "8081"
    }
  },
  {
    "name":         "app-2",
    "script":       "app-2.js",
    "instances":    3,
    "merge_logs":   true,
    "env": {
        "NSOLID_COMMAND": "localhost:9001",
        "NSOLID_APPNAME": "app-2",
        "NODE_ENV": "production",
        "PORT":     "8082"
    }
  }
]}

pm2-34.json:

{ "apps": [
  {
    "name":         "app-3",
    "script":       "app-3.js",
    "instances":    3,
    "merge_logs":   true,
    "env": {
        "NSOLID_COMMAND": "localhost:9001",
        "NSOLID_APPNAME": "app-3",
        "NODE_ENV": "production",
        "PORT":     "8083"
    }
  },
  {
    "name":         "app-4",
    "script":       "app-4.js",
    "instances":    3,
    "merge_logs":   true,
    "env": {
        "NSOLID_COMMAND": "localhost:9001",
        "NSOLID_APPNAME": "app-4",
        "NODE_ENV": "production",
        "PORT":     "8084"
    }
  }
]}

The examples assume you have pm2 installed globally, via

npm install -g pm2

To start your applications, issue the following command:

$ pm2 start pm2-12.json
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Process launched
[PM2] Process launched
┌──────────┬────┬─────────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode    │ pid  │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼─────────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app-10  │ cluster │ 4375 │ online │ 00s     │ 28.543 MB   │ disabled │
│ app-11  │ cluster │ 4376 │ online │ 00s     │ 29.176 MB   │ disabled │
│ app-12  │ cluster │ 4379 │ online │ 00s     │ 29.086 MB   │ disabled │
│ app-23  │ cluster │ 4384 │ online │ 00s     │ 29.004 MB   │ disabled │
│ app-24  │ cluster │ 4385 │ online │ 00s     │ 28.922 MB   │ disabled │
│ app-25  │ cluster │ 4388 │ online │ 00s     │ 20.727 MB   │ disabled │
└──────────┴────┴─────────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

At this point, you can see both app-1 and app-2 instances in N|Solid as
app-1 and app-2 as expected.

Please note that the previously advised solution of passing the N|Solid
configuration environment variables to pm2 is no longer recommended. If you
are still doing this, these variables will take precedence over the ones in
your pm2 config file, and you will continue to see the pm2 supervisor
process in your applications. By following the preceding instructions, this
should no longer be visible.

Programmatic configuration

If your N|Solid connectivity or metadata is not known at the time of pm2
configuration, you have the option of configuring the N|Solid agent using the
Node API provided with N|Solid 2.0. This can be performed by invoking the
start method on the nsolid module.

require('nsolid').start({
  'command': 'localhost:9001',
  'app': 'app-5',
  'tags': ['some', 'nsolid', 'tags']
})

If any environment variables are present in process.env, they will be used if
the corresponding attributes are not set in the config object passed to
start. The complete mapping of environment to attribute is as follows:

NSOLID_COMMAND => "command"
NSOLID_DATA => "data"
NSOLID_BULK => "bulk"
NSOLID_PUBKEY => "pubkey"
NSOLID_APPNAME => "app"
NSOLID_TAGS => "tags"

The value for tags may be either an array of tags, or a comma-delimited
string as would be set in NSOLID_TAGS

Be aware that if the N|Solid agent has been initialized by the environment,
calling the start method will not cause these values to take effect. You
should only expect one method to be effective at a time.

Running multiple apps

Due to the change in configuration, it is also no longer necessary to run
multiple pm2 processes to get the correct NSOLID_APPNAME or NSOLID_TAGS,
although it is still safe to do so.

Testing that everything works fine

From the N|Solid Console, you'll now see all 4 apps. These are all web servers
running on ports 8081-8084, so you can send them some http traffic with an
Apache Bench invocation like:

ab -t 20 -c 10 http://localhost:8081/

This will send requests to the app-1 server instances (3, on port 8081) for
20 seconds, with 10 concurrent requests running. When viewing the "app-1" app
in N|Solid, you should see 3 of the instances start using CPU (move to the
right).