Detach child node process after receiving first message

I am building a system with node.js where a user can invoke workflows from a web interface and I am having problems combining these two criteria for the system:

  • The web server process and workflow must run independently, so if the web server goes down, the workflow is not affected.
  • The parent process must be able to receive at least one initial message from the worker process. Following this post, I want to log the exit from the workflow to a file.

I was able to fulfill both criteria on my own, but not together. This is what the relevant parts of my code look like:

function spawnWorker (id, callback) {
    var worker = spawn("node", [require.resolve("worker"), id], {
        detached: true,
        stdio: ["ignore", "pipe", "pipe"]
    });

    worker.unref();

    var logfile = fs.createWriteStream("foo.log");

    worker.stdout.once("data", function (data) {
        worker.stdout.pipe(logfile);
        worker.stderr.pipe(logfile);

        callback(undefined, data.toString());
    });
}

      

This meets criteria 2 (i.e., receives the first message from the worker and redirects all subsequent output to a file), but if I kill the mother process, the worker process is also killed, although the output was redirected.

I assume this is because the worker stdout and stderr are piped to the parent process before they are sent to the file stream. If I were to pass a thread when the process spawns, according to the docs , node instead duplicates this thread in the worker process:

The thread descriptor underlying the file is duplicated in the child process [...]

Is there a way to remove the connection between the parent process and the worker process after receiving the first message? Or should I be using some type of RPC to accomplish this, and if so what would be a good choice for this one post communication?

+3


source to share


1 answer


I solved this by using a node net

module to create a server on a random port that is passed to the worker when it starts (so it knows where to send the response when it's ready).

Here is an example implementation of my solution to clarify it meets the requirements:

  • saving the output of the workflow log,
  • keeping the workflow separate from the parent process (so that if the last one crashes, it doesn't affect the worker)

server.js



var net = require("net"),
    fs = require("fs"),
    spawn = require("child_process").spawn,
    randomPort = require("get-port");

randomPort(function (port) {
    var server = net.createServer(function (connection) {
        connection.on("data", function (data) {
            server.close();
            /**
             * Response received from worker, this is where you would put
             * your logic that returns a response to the client that initiated
             * the request to the server.
             */
        });
    });

    server.listen(port);

    var logfile = fs.createWriteStream("log");
    var worker = spawn("node", ["worker.js", port], {
        detached: true,
        stdio: ["ignore", logfile, logfile]
    });

    worker.unref();

    worker.on("close", function (status, message) {
        console.log("worker closed", status, message);
    });
});

      

worker.js

var net = require("net");

var options = process.argv.slice(2),
    rpcPort = Number(options[1]);

var client = net.connect({port: rpcPort}, function () {
    client.end(JSON.stringify({started: true}}));
});

      

0


source







All Articles