2

I would like to control a few web sites using a UI to start and stop them, changing the ports that the different web server's listen to.

PM2 is a command line utility to manage node sites, but does not have a user interface that I can supply my customer.

How can I run a node.js web site from within another node.js web application.

The following node.js code does not seem to do the work.

const { exec } = require('child_process');

....

exec('node app.js', (err, stdout, stderr) => {
    if (err) {
        console.log(`err: ${err}`);
        return;
    }

    // the *entire* stdout and stderr (buffered)
    console.log(`stdout: ${stdout}`);
    console.log(`stderr: ${stderr}`);
});

note: regular linux commands instead of the 'node app.js' command work as expected.

  • if (err) { console.log(error); return; } – Subin Sebastian Mar 25 '18 at 09:38
  • what is the error printed? – Subin Sebastian Mar 25 '18 at 09:38
  • @Subin Nothing shows up. I will try to play around and see if an error is generated that i missed out some how. If I succeed I will revise the question accordingly. –  Mar 25 '18 at 09:47
  • @Subin - to answer your question - if the called node.js application generates an error it is correctly printed. but if no error occurs the new node.js instance does not seem to start even though no error is displayed. –  Mar 25 '18 at 10:12
  • The error received is: Command failed: node app.js –  Mar 25 '18 at 11:01
  • @JulianPollak It looks like node is not in `PATH`. You could try `'"' + process.execPath + '"` instead of `node`, which contains the full path of the node executable to verify if that is the issue. – Andrés Andrade Mar 25 '18 at 11:10
  • @AndrésAndrade Thanks for your assistance. –  Mar 25 '18 at 12:19
  • Note: I have replaced the exec with spawn - the exec would only print out information once the process terminated. –  Mar 25 '18 at 12:32

2 Answers2

2

Got the following code to work in case you want to run the same: This is the code on the server that will spawn a new web server.

app.get('/start', ( req, res ) => {

    var node = spawn('node', ['app.js &'], { shell: true });

    node.stdout.on('data', function (data) {
      console.log('stdout: ' + data.toString());
    });

    node.stderr.on('data', function (data) {
      console.log('stderr: ' + data.toString());
    });

    node.on('exit', function (code) {
      console.log('child process exited with code ' + 
        code.toString());
    });

    // Notify client 
   res.status(200).send( {} );
});
  • Note: If your child node process is in a different directory than the parent node process, you can set the working directory in the third parameter of the spawn command: { shell: true, cwd: "your child working directory" }. –  Mar 25 '18 at 13:34
1

The simplest alternative would be to keep a collection of ExpressJS instances and create/destroy them as needed within NodeJS:

const express = require("express");

var app1 = express();
app1.use("/", function(req, res){ res.send("APP 1"); });

var app2 = express();
app2.use("/", function(req, res){ res.send("APP 2"); });

// start them
var server1 = app.listen(9001);
var server2 = app.listen(9002);

// close the first one
server1.close();

// port 9001 is closed
// port 9002 is still listening

However, if you need to spawn independent processess, you could have:

const { spawn } = require("child_process");

// Prevent Ctrl+C from killing the parent process before the children exit
process.on("SIGINT", () => {
  console.log("Terminating the process...");
  if (runningProcesses > 0) {
    setTimeout(() => process.exit(), 3000);
  } else {
    process.exit();
  }
});

function asyncSpawn(command, parameters = []) {
  return new Promise((resolve, reject) => {
    runningProcesses++;
    console.log(command, ...parameters, "\n");

    spawn(command, parameters, {
      stdio: "inherit"
    })
      .on("close", code => {
        if (code)
          reject(new Error(command + " process exited with code " + code));
        else resolve();
      })
      .on("exit", error => {
        runningProcesses--;
        if (error) reject(error);
        else resolve();
      });
  });
}

And launch new processes like this:

asyncSpawn("node", ["server.js", "--param1"])
    .then(() => console.log("DONE"))
    .catch(err => console.error(err));
brickpop
  • 2,754
  • 1
  • 13
  • 12