【问题标题】:Execute code in node.js from a child process从子进程执行 node.js 中的代码
【发布时间】:2018-05-11 05:33:00
【问题描述】:

node.js 的新手我正在尝试在模块的子进程中执行一些代码。

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

var server = http.createServer(handleRequest);

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

当一个 url 被获取时,我启动一个子进程:

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 不为空(我可以打印它的值) 所以我的问题是我需要在 worker.js 中导入/执行什么操作,以便它可以从 firebase 模块执行代码?我尝试用户要求...但没有任何效果。 我的问题也更笼统,我想在另一个文件中编写一些帮助程序(创建、读取、删除),但我会遇到同样的问题。 感谢您的任何帮助。

【问题讨论】:

  • 为什么你认为有必要使用子进程?我没有看到任何暗示它们是必要的东西,并且使用子进程会带来不可忽略的性能损失。
  • 我需要使用子进程来释放内存,这是一个经常调用的繁重任务,这是我发现进程完成后真正释放内存的唯一方法。

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


【解决方案1】:

您不能将实时 Javascript 对象传递给另一个进程。如果对象仅包含 Javascript 数据,您可以使用 JSON 对其进行序列化并将其传递给将反序列化副本的其他进程,但这不适用于具有本机代码或背后的 TCP 连接的对象,这很可能您打开的数据库句柄代表什么。在某些情况下,您可以将 TCP 连接传递给另一个进程(集群会这样做),但如果您将它包装在另一个连接对象中(通常是这样),那么用在另一个进程中传递的 TCP 连接。就个人而言,我宁愿避免所有这些麻烦。

除非您的子进程中有繁重的 CPU 工作,否则我认为没有任何理由需要子进程。当请求进来时,你可以在主进程中做任何你想做的数据库工作。数据库工作应该主要是异步的,因此不应该阻塞主 node.js 线程,你应该能够有多个请求在飞行中同时。有很多请求,你的数据库无论如何都会成为瓶颈,而不是主要的 node.js 进程。

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

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

【讨论】:

  • 嗯,谢谢你的解释,是的,我有大量的进程要运行(每 30 秒一次,每分钟一次,每 5 次,每 10 次......)处理大量数据,我有 16 GB 内存,这是我发现释放内存的唯一方法,当子进程结束时,一切都被释放,我的服务器可以运行这个进程一个月而无需重新启动,因为内存不足错误。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 2023-03-19
  • 2012-11-02
  • 2021-05-30
  • 1970-01-01
相关资源
最近更新 更多