使用Node.js和mongodb处理超时

我目前正在testing一些代码如何站在以下的情况:

  • Node.js应用程序启动并成功build立到mongodb的连接
  • 在成功build立连接之后,mongodb服务器将停止,所有后续请求都会失败

要做到这一点,我已经得到了使用官方驱动程序(在这里find: https : //github.com/mongodb/node-mongodb-native )的代码:

MongoClient.connect('mongodb://localhost:27017/testdb', function(err, db) { app.get('/test', function(req, res) { db.collection('users', function (err, collection) { console.log(err); if (err) { // ## POINT 1 ## // Handle the error } else { collection.find({ 'username': username }, { timeout: true }).toArray(function(err, items) { console.log(err); if (err) { // ## POINT 2 ## // Handle the error } else { if (items.length > 0) { // Do some stuff with the document that was found } else { // Handle not finding the document } } }); } }); }); 

});

由于在处理请求时,MongoDB服务器不再运行,所以我做了一个假设,即在标记为## POINT 1 ##或## POINT 2 ##的点上,它会返回一个错误,指示超时 但是,这并非如此。

我已经尝试了许多不同的设置(包括你可以在这里看到明确允许光标超时),但我似乎无法以任何方式启用它。 在我尝试过的每一个configuration中,Node.js都会继续等待find()操作来callback,而它从来不会这样做。

如果运行mongodb 之前启动Node.js应用程序,它会捕获连接callback中的错误,但如果连接在此之后死亡,则似乎无法处理它。

有没有我缺less的设置,或者有没有办法检测连接被build立后被终止?

编辑:只是要清楚,find方法中使用的用户名variables实际上是在我的完整代码中声明的,我已经放在这篇文章中的代码是一个减less版本来说明结构和错误检查。

UPD:
基于这篇文章,看起来他们已经部署了修复程序,这将与我们在这里所做的一样。 不知道这是否已经在npm(15.10.13)。 https://github.com/mongodb/node-mongodb-native/issues/1092#ref-commit-2667d13

经过一番调查,我已经设法了解那里发生了什么事情:
每次调用任何方法来处理数据库(查找,更新,插入等)时,都会创build具有自己ID的游标,并将其自身注册到Db的EventEmitter中以供稍后调用。 与此同时,它将自己注册到同一个CallBackStore中的_notReplied对象。

但是一旦连接closures了,我就找不到任何可以通过_notReplied游标进行迭代的东西,并且会用错误或任何具有定时器的逻辑触发它们(它仍然可能在某处)。 所以我设法写了一些小的工作,当DB发出close事件时,强制触发错误的游标出现错误:

 new mongodb.Db('testdb', new mongodb.Server('localhost', 27017, { }), { safe: true }).open(function (err, db) { if (!err) { db.on('close', function() { if (this._callBackStore) { for(var key in this._callBackStore._notReplied) { this._callHandler(key, null, 'Connection Closed!'); } } }); // ... } else { console.log(err) } }); 

我build议使用第一种方法,而不是MongoClient。 原因很less:例如,当你closures连接,然后调用.find它将正确地触发callback错误,而与MongoClient不会。

如果你正在使用MongoClient:

 MongoClient.connect('mongodb://localhost:27017/testdb', function(err, db) { if (!err) { db.on('close', function() { if (this._callBackStore) { for(var key in this._callBackStore._notReplied) { this._callHandler(key, null, 'Connection Closed!'); } } }); // ... } else { console.log(err); } }); 

这会做什么? 一旦连接closures,它将遍历所有_notReplied游标,并触发错误Connection Closed!他们的事件Connection Closed!

testing用例:

 items.find({ }).toArray(function(err, data) { if (!err) { console.log('Items found successfully'); } else { console.log(err); } }); db.close(); 

这将强制closures数据库连接并触发您之前处理的close事件,并确保光标将被closures。

UPD:我已经在GitHub上添加了问题: https : //github.com/mongodb/node-mongodb-native/issues/1092我们将看到他们对此的评论。

我有同样的问题,并从谷歌find这个网页。 但你select的答案没有解决问题,它是一样的,this._callBackStore不能使用

但我试图包装蒙戈,似乎工作正常

 var MongoClient = require('mongodb').MongoClient; var mongo = {}; mongo.init = function() { MongoClient.connect('mongodb://localhost:27017/testdb', function(err, db) { if (err) { mongo.DB = ''; } else { mongo.DB = db; } db.on('close', function() { mongo.DB = ''; }); db.on('reconnect', function() { mongo.DB = db; }); } } mongo.getdb = function(callback) { if (mongo.DB) { callback(null, mongo.DB); } else { callback('can not connect to db', null); } } module.exports = mongo; 

经过一些进一步的调查,似乎你不能指定“离线”超时,如在上述情况。 唯一可以指定的超时时间是通知服务器在非活动状态10分钟后超时的情况,但是在上面与服务器的连接closures的情况下,这不起作用。

作为参考,我在这里find了这个信息: https : //github.com/mongodb/node-mongodb-native/issues/987#issuecomment-18915263我相信谁是这个项目的主要贡献者之一。

我正在和Hapi和Mongodb(w / omongoose)进行交stream。 特征:

  1. 只有当mongo数据库可用时才开始响应API请求
  2. 如果mongo在周期中死亡,请停止响应
  3. 当mongo再次可用时重新开始
  4. 保持所有请求的单一连接

结合其他答案和这篇文章的一些想法https://productbuilder.wordpress.com/2013/09/06/using-a-single-global-db-connection-in-node-js/我的做法是这样的:

server.js

 Utilities.initializeDb(() => { server.start((err) => { if (err) throw err; console.log('Server running at:', server.info.uri); }); }, () => { server.stop((err) => { if (err) throw err; console.log('Server stopped'); }); }); 

Utilities.js

 "use strict"; const MongoClient = require('mongodb').MongoClient; const MongoUrl = 'mongodb://localhost:27017/db'; export const Utilities = { initializeDb: (next, onCrash) => { const ConnectToDatabase = (params) => { MongoClient.connect(MongoUrl, (err, db) => { if (err !== null) { console.log('#t4y4542te Can not connect to mongo db service. Retry in 2 seconds. Try #' + params.retry); console.error(err); setTimeout(() => { ConnectToDatabase({retry: params.retry + 1}); }, 2000); } else { db.on('close', () => { onCrash(); console.log('#21df24sf db crashed!'); ConnectToDatabase({retry: 0}); }); global.db = global.db || db; next(); } }); }; ConnectToDatabase({retry: 0}); } }; 

我将数据库连接导出到全局空间。 这感觉不是最好的解决scheme,但我有数据库连接作为parameter passing给所有模块,并吸了更多的项目。 也许应该有一些模块化的方法,在你需要的地方导入数据库连接,但在我的情况下,我几乎需要在任何地方使用它,我将不得不在大多数文件中编写include语句。 这个API是无意义的连接到分贝,所以我认为这可能是最好的解决scheme,即使我反对在全球空间神奇飞行的东西..