使用Node.js和mongodb处理超时

ras*_*ing 18 javascript error-handling timeout mongodb node.js

我目前正在测试一些代码如何抵制以下场景:

  • 启动Node.js应用程序并成功建立与mongodb的连接
  • 成功建立连接后,mongodb服务器将死亡,所有后续请求都将失败

要做到这一点,我有以下代码,使用官方驱动程序(在这里找到: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
                    }
                }
            }); 
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

});

由于mongodb服务器在处理请求时不再运行,我假设在我标记为## POINT 1 ##或## POINT 2 ##的点上,它将返回错误指示超时; 然而,事实并非如此.

我已经尝试了许多不同的设置(包括你可以在这里明确允许光标超时的设置),但是我似乎无法以任何方式启用它.在我尝试过的每个配置中,Node.js都会一直等待find()操作进行回调,但它永远不会.

如果我运行mongodb 之前启动Node.js应用程序,它会很好地捕获连接回调中的错误,但如果连接在此之后死亡,它似乎无法以任何方式处理它.

是否存在我缺少的设置,或者在建立连接后无法检测到连接被终止?

编辑:为了清楚起见,find方法中使用的用户名变量实际上是在我的完整代码中声明的,我在这篇文章中添加的代码是一个简化版本来说明结构和错误检查.

mok*_*oka 11

UPD:
基于这篇文章,看起来他们已经部署了与我们在这里做的相同的修复.不确定这是否已经在npm(15.10.13)内.https://github.com/mongodb/node-mongodb-native/issues/1092#ref-commit-2667d13

经过一些调查后,我已经设法理解那里发生了什么:
每次调用任何方法处理数据库(查找,更新,插入等)时,它都会创建游标,它有自己的ID并将自己注册到Db的EventEmitter因为后来被召回 同时,它将自身注册到同一个CallBackStore中的_notReplied对象.

但是一旦连接关闭,我找不到任何会迭代_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)
  }
});
Run Code Online (Sandbox Code Playgroud)

我建议使用第一种方法而不是MongoClient.原因很少:例如,当您关闭连接然后调用.find它将在回调中正确触发错误,而使用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);
  }
});
Run Code Online (Sandbox Code Playgroud)

这会怎么做?一旦连接关闭,它将遍历所有_notReplied游标并为它们触发错误的事件Connection Closed!.

测试用例:

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

这将强制关闭数据库连接并触发close您之前处理的事件,并确保将关闭游标.

UPD:我在GitHub上添加了问题:https://github.com/mongodb/node-mongodb-native/issues/1092我们会看到他们对此有何看法.