从subprocess执行node.js中的代码

新的node.js我试图从一个模块的subprocess中执行一些代码。

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

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

当一个URL被提取时,我启动一个subprocess:

 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文件执行一些代码,我设法从我的服务器传递一些数据到我的subprocess,使用['./worker.js', path.substring(1)]

我使用firebase来执行一些操作,所以在我的worker.js中初始化我的firebasepipe理员,凭据和数据库:

 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数据库作为参数给我的孩子,所以我不会在每次启动一个进程时创build一个对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()]) 

我只是将数据库作为parameter passing给我的工作者。 然后在我的工人,我得到的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); }); } 

但是当我到达一个url,我得到一个错误:

 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模块执行代码? 我试图用户需求…但没有什么工作。 我的问题也是比较普遍的,我想写一些助手(创build,读取,删除)在另一个文件,但我会得到同样的问题。 感谢您的任何帮助。

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

除非你的subprocess中有大量的CPU工作,否则我并不认为有任何理由需要一个subprocess。 在请求进来的时候,你可以在主进程中做任何你想要的数据库工作。数据库工作应该大部分是asynchronous的,因此不应该阻塞主要的node.js线程,你应该能够在同一时间。 有了很多的请求,你的数据库将成为瓶颈,而不是主要的node.js过程。

如果您有合法的理由使用subprocess,并且不想为每个进程打开和closures新的数据库连接,那么您可能需要创build一堆打开的工作进程并保持打开状态。 然后,他们可以打开自己的连接到数据库并保持打开状态。 当一个新的请求到达你的主要node.js进程时,你使用某种forms的IPC(也许只是写入subprocess的标准input)来发送一个新的工作,它只是坐在那里等待处理。 您可以通过决定您应该有多less工作stream程来优化吞吐量来优化。 然后,当新的工作进来时,你只需要把工作放到一个队列中。 如果有空闲的工人,你可以把队列中的下一份工作发给那个工人。 每当工作人员完成一项工作时,就会检查队列中是否有其他项目发送该工作人员。

这样做,你不会创build和杀死与你的数据库的新连接,每个工作进程可以拥有并保持自己的数据库连接。