我想将MongoDB数据库作为child_process运行,因为某些数据库操作需要花费大量时间,我不希望应用程序的其余部分冻结。
我能够将数据库代码放入一个模块中,该模块通过child_process中的事件发射器进行响应和重新生成。
以下是简化版本中的代码(db-process.js):
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/myproject';
var db = null;
MongoClient.connect(url, function(err, database) {
if(err){
console.warn('Connection to MongoDB failed.');
}else{
db = database;
console.log('Connected to MongoDB.');
}
});
process.on('message', function(msg) {
switch(msg.name){
case 'getRecord':
var collection = db.collection('SomeTable');
collection.find({id: 'someId').toArray(function(err, docs) {
if(!err) process.send{'name': 'getRecord', record: records[0]});
});
break;
case 'saveRecord':
// Code here...
break;
}
});
挑战在于我希望能够通过传递回调函数来使用数据库模块。这将使我更容易在我的所有其他模块中使用。但是如何将事件中的变量放入回调函数中呢?这甚至可能吗?
下面显示了我在简化版本(db-controller.js)中未完成的尝试:
var childProcess = require('child_process');
var dbProcess = childProcess.fork('./db-process.js');
dbProcess.on('message', function(msg) {
switch(msg.name){
case 'getRecord':
var record = msg.record;
break;
case 'saveRecord':
// Handling here...
break;
}
});
var controller = {};
controller.getRecord = function(onQueryDone){
dbProcess.send({name: 'getRecord'});
// How to call the callback function with data when it is received? Basicly want the record variable from the switch.
onQueryDone(record);
};
controller.saveRecord = function(record, onQueryDone){
dbProcess.send({name: 'saveRecord'});
// Handling...
};
module.exports = controller;
所以我希望能够像这样使用这个模块:
var dbController = require('./db-controller.js');
dbController.getRecord(function(record)){
// Do something with record...
});
有关如何实现这一目标的任何想法?
答案 0 :(得分:0)
据我所知,您无法在节点实例(主实例和分叉实例)之间传递回调,但您可以传递数据。
您在案例中使用的是工作池模块,其中工作者实例将处理所有数据库查询,主服务器(池实例)将数据发送给这些工作人员并在完成后收集结果
这是我在github forked-worker-pool上提供的一个,但在npm还有其他一些选择。
答案 1 :(得分:0)
另一种选择是完全解耦您的流程。我之前在Amazon上使用过SQS,我将数据放入队列,还有另一个服务器/进程监听这些项目,唤醒并处理它们。这是一个非常简单的模型。如果您不在AWS上,您可能会使用像rabbitmq这样的东西。这样你的应用服务器永远不会被阻止,因为它只是将数据转储到队列并继续。