Unitech / pm2

Node.js Production Process Manager with a built-in Load Balancer.
https://pm2.keymetrics.io/docs/usage/quick-start/
Other
41.56k stars 2.62k forks source link

Can pm2 ecosystem support promise config #2648

Open kimown opened 7 years ago

kimown commented 7 years ago

Hi, I am using pm2 start ecosystem.config.js to start my multiple express projects, I use detect-port in each express project to avoid using used ports. Because free port is a dynamic number, so I want to show port in App name when I run pm2 list

┌──────────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────┬────────┬──────────┐
│ App name     │ id │ mode │ pid   │ status │ restart │ uptime │ cpu │ mem    │ watching │
├──────────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────┼────────┼──────────┤
│ script       │ 0  │ fork │ 33473 │ online │ 4       │ 6h     │ 0%  │ 0 B    │ disabled │
│ specify port │ 12 │ fork │ 35716 │ online │ 0       │ 2h     │ 0%  │ 0 B    │ disabled │
└──────────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────┴────────┴──────────┘

I searched some issues, the only way I found doing this is change the name before run pm2 start ecosystem.config.js.

const apps = [
    {
        name:'specify port',
        script    : "app.js",
    },
    {
        name:'script',
        script    : "web.js"
    }
];
module.exports = apps;

So if pm2 can support promise config, my code can look like this:

const detect = require('detect-port');

function getPorts(basePort, number) {
    let ports = [];
    return new Promise((resolve)=>{
        const cb = (err, _port) => {
            if (err) {
                console.log(err);
            }
            ports.push(_port)
            if(ports.length<number){
                detect(_port+1, cb)
            }else {
                resolve(ports)
            }
        }

        detect(basePort, cb);
    })
}

const apps = [
    {
        name:'specify port',
        script    : "app.js",
    },
    {
        name:'script',
        script    : "web.js"
    }
];

function getApp() {
    return new Promise((resolve)=>{
        getPorts(3000, apps.length).then((data)=>{
            const appCopy = apps.map((v,k)=>{
                return Object.assign(v,{name:v.name+data[k]})
            })
            resolve(appCopy)
        })
    })
}

module.exports = getApp()

Or can you give me other suggestions, thanks.

soyuka commented 7 years ago

Would be a nice feature IMO!

kimown commented 7 years ago

If the PR merged, you can run pm2 start ecosystem.config.js like this:

ecosystem.config.js


const detect = require('detect-port');

function getPorts(basePort, number) {
  let ports = [];
  return new Promise((resolve) => {
    const cb = (err, _port) => {
      if (err) {
        console.log(err);
      }
      ports.push(_port)
      if (ports.length < number) {
        detect(_port + 1, cb)
      } else {
        resolve(ports)
      }
    }

    detect(basePort, cb);
  })
}

const apps = [
  {
    name: 'web1',
    script: 'web.js'

  },
  {
    name: 'web2',
    script: 'web.js'
  }
];

function getApps() {
  return new Promise((resolve) => {
    getPorts(8080, apps.length).then((data) => {
      const appCopy = apps.map((v, k) => {
        return Object.assign(v,
          {
            name : v.name + " :" + data[k]
          },
          {
            env: {
              PORT: data[k]
            }
          }
        )
      })
      resolve(appCopy)
    })
  })
}

module.exports = getApps()

web.js

var express = require('express')
var app = express();
const openBrowser = require('react-dev-utils/openBrowser');
const PORT = process.env.PORT;

app.get('/', function (req, res) {
    res.send('web.js '+PORT)
})

app.listen(PORT, function () {
  console.log(`Example app listening on port !${PORT}`);
  const openUrl = `http://localhost:${PORT}`;
  openBrowser(openUrl)
})

Also, you can use args in ecosystem.config.js to pass the port parameter .

    args: [
      '--env.port=2333',
    ],

then in web.js

const argv = require('yargs').argv;
const PORT = argv.env.port

http://pm2.keymetrics.io/docs/usage/application-declaration/

cKehres commented 6 years ago

Still not possible? I would start apps based on database entries

kimown commented 6 years ago

@cKehres

http://pm2.keymetrics.io/docs/usage/pm2-api/

use pm2 as node module, it works well, I use it in my company project.

makidoll commented 3 years ago

I hope this becomes a feature soon! I've been using child_process execSync to get stuff inside a consistent Docker container. Here's an example:

const child_process = require("child_process");
const ip = child_process.execSync("curl http://api.ipify.org").toString()
// use ip wherever