从子进程

时间:2017-11-27 21:27:58

标签: javascript node.js firebase firebase-realtime-database

node.js的新手我试图从模块中执行子进程中的某些代码。

让我解释一下,我在index.js中有我的简单服务器

var server = http.createServer(handleRequest);

server.listen(PORT, function(){
    console.log("Server listening on: http://localhost:%s", PORT);
});

当提取网址时,我启动子进程:

function handleRequest(req, res){  
    console.log('Request path = ' + req.url)
    launchWorker(req.url)
    res.end('Path Hit: ' + req.url);
}

// workers execution 
function launchWorker(path) {
    const worker = child_process.spawn('node', ['./worker.js', path.substring(1)])

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

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

    worker.on('close', function(code, signal) {
        console.log('child process exited with code: ' + code)
    }); 
}  

所以我有一个执行某些代码的worker.js文件,我设法使用['./worker.js', path.substring(1)]

将一些数据从我的服务器传递到我的子进程

我使用firebase执行某些操作,因此在我的worker.js中,我初始化了我的firebase管理员,凭据&数据库:

var admin = require("firebase-admin");

var serviceAccount = require("./service_account.json");

var defaultApp = admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "http://myAdress.firebase"
});

var db = admin.database()

performWork()

function performWork() {

    var arg = process.argv[2]
    var ref = db.ref("something");
    ref.once("value", function(snapshot) {
      console.log(arg);
      process.exit(1); 
    });

}

我每分钟都要启动一个进程,所以我想要做的就是将firebase数据库作为参数提供给我的孩子,所以每次启动进程时都不会创建对firebase的访问权限。 所以这就是我在index.js中尝试做的事情:

var admin = require("firebase-admin");

var serviceAccount = require("./service_account.json");

var defaultApp = admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "http://myAdress.firebase"
});

var db = admin.database()

...

function launchWorker(path) {
    const worker = child_process.spawn('node', ['./worker.js', path.substring(1), admin.database()])

我只是将数据库作为参数传递给我的工作人员。 然后在我的工作人员上我得到了fb:

function performWork() {

    var arg = process.argv[2]
    var db = process.argv[3]
    var ref = db.ref("something");
    ref.once("value", function(snapshot) {
      console.log(arg);
      process.exit(1); 
    });

}

但是当我到达网址时,我收到了一个错误:

TypeError: db.ref is not a function
    at performWork (/home/user/worker.js:12:15)
    at Object.<anonymous> (/home/user/worker.js:6:1)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3

我认为worker.js根本不知道firebase,并且无法访问函数.ref。即使db不为null(我可以打印它的值) 所以我的问题是我需要在worker.js中导入/执行什么,以便它可以从firebase模块执行代码?我试图用户要求......但是没有用。 我的问题也更一般,我想在另一个文件中写一些帮助(创建,读取,删除),但我会遇到同样的问题。 感谢您的任何帮助。

1 个答案:

答案 0 :(得分:1)

您无法将实时Javascript对象传递给其他进程。如果该对象只包含Javascript数据,您可以使用JSON对其进行序列化,并将其传递给另一个将反序列化副本的进程,但这对于具有本机代码或其后面的TCP连接的对象不起作用,很可能是您的开放数据库句柄所代表的。在某些情况下,您可以将TCP连接传递给另一个进程(聚类会这样做),但是如果您将它包装在另一个连接对象(通常是这样)中,那么它需要一大堆工作才能重新构建一个连接对象与另一个进程中传递的TCP连接。就个人而言,我宁愿避免一切麻烦。

除非你的子进程中有大量的CPU工作,否则我真的没有理由在这里需要一个子进程。当请求进入时,您可以在主进程中执行您想要的任何数据库工作。数据库工作应该主要是异步的,因此不应该明显阻止主节点.js线程,并且您应该能够在飞行中有多个请求同一时间。对于大量请求,无论如何,您的数据库将成为瓶颈,而不是主node.js进程。

如果您有正当理由使用子进程并且您不想为每个进程打开和关闭新的数据库连接,那么您可能希望创建一组打开的工作进程并保留它们打开。然后,他们可以打开自己与数据库的连接并保持打开状态。当一个新请求到达你的主node.js进程时,你使用某种形式的IPC(也许只是写入子进程的stdin)向它发送一个新的工作,它只是坐在那里等待处理。您可以通过决定优化吞吐量所需的工作流程来优化事物。然后,当有新作业进入时,您只需将作业放入队列即可。如果有任何免费工作人员,则将队列中的下一个作业发送给该工作人员。每次工作人员完成工作时,您都会检查队列中是否有另一个项目来发送该工作人员。

这样做,您不会一直创建和终止与数据库的新连接,并且每个工作进程都可以拥有并保持自己的数据库连接。