收到第一条消息后,分离节点子进程

时间:2015-04-27 12:57:03

标签: javascript node.js

我正在使用node.js构建一个系统,用户可以从Web界面生成工作进程,而我在系统中将这两个标准组合起来时遇到了问题:

  1. Web服务器进程和工作进程应独立运行,以便在Web服务器崩溃时,工作进程不受影响。
  2. 母进程应该能够从工作进程接收至少一条初始消息。在该消息之后,我想将工作进程的输出记录到文件中。
  3. 我已经能够自己完成这两个标准,但不能一起完成。以下是我的代码目前的相关部分:

    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());
        });
    }
    

    这符合条件2(即,它接收来自worker的第一条消息,并将所有后续输出重定向到文件),但是如果我杀死了母进程,则即使输出已被删除,也会终止工作进程重定向。

    我的猜测是,这是因为工作人员的stdout和stderr在被发送到文件流之前被传送到母进程。如果我在生成进程时传入流,根据docs,节点将在工作进程中复制该流:

      

    流的基础文件描述符在子进程[...]

    中重复

    有没有办法在收到第一条消息后删除母进程和工作进程之间的连接?或者我应该使用某种类型的RPC来实现这一点,如果是这样,一旦通信,这对一条消息会有什么好的选择?

1 个答案:

答案 0 :(得分:0)

我使用节点的net模块解决了这个问题,在一个随机端口上生成服务器,该服务器在启动时传递给工作人员(因此它知道在准备就绪时将响应发送到哪里)。

以下是我的解决方案的实施示例,澄清一下,这符合以下要求:

  1. 保存工作进程的日志输出,
  2. 保持工作进程与母进程分离(如果后者崩溃,则不会影响工作人员)
  3. 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}}));
    });