Javascript 使用Node.js和mongodb处理超时

Javascript 使用Node.js和mongodb处理超时,javascript,node.js,mongodb,error-handling,timeout,Javascript,Node.js,Mongodb,Error Handling,Timeout,我目前正在测试一些代码如何对抗以下场景: Node.js应用程序已启动并成功建立到mongodb的连接 成功建立连接后,mongodb服务器死亡,所有后续请求失败 为此,我获得了以下代码,该代码使用了官方驱动程序(可在此处找到:): })) 由于mongodb服务器在处理请求时不再运行,我假设在我标记为###点1##或###点2#的点上,它将返回一个指示超时的错误;然而,事实并非如此 我尝试了许多不同的设置(包括您可以在这里看到的明确允许光标超时的设置),但是我似乎无法以任何方式启用它。在我

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

  • Node.js应用程序已启动并成功建立到mongodb的连接
  • 成功建立连接后,mongodb服务器死亡,所有后续请求失败
为此,我获得了以下代码,该代码使用了官方驱动程序(可在此处找到:):

}))

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

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

如果我在运行mongodb之前启动Node.js应用程序,它会在connect回调中捕获错误,但如果在此之后连接终止,它似乎不会以任何方式处理它

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


编辑:需要澄清的是,find方法中使用的username变量实际上是在我的完整代码中声明的,我在本文中使用的代码是一个简化版本,用于说明结构和错误检查。

经过进一步的调查,似乎您无法指定“脱机”超时,如上述场景中所述。唯一可以指定的超时是在10分钟不活动后通知服务器使光标超时的超时,但是与上面的场景一样,与服务器的连接断开,这不起作用

作为参考,我在这里找到了以下信息:我认为是该项目主要贡献者之一的人。

UPD:
根据这篇文章,看起来他们已经部署了修复程序,它将和我们在这里所做的一样。不确定这是否已经在npm内(15.10.13)

经过一番调查,我终于了解了那里的情况:
每次调用任何处理数据库的方法(查找、更新、插入等)时,它都会创建一个游标,该游标有自己的ID,并将自己注册到Db的EventEmitter,以便稍后调用。同时,它将自己注册到同一CallBackStore中的_notrepled对象

但一旦连接关闭,我就找不到任何可以通过NotResponsed游标进行迭代并通过错误或计时器的任何逻辑触发它们的东西(它仍然可能在某处)。因此,我设法编写了一些小的变通方法,当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)
  }
});
我建议使用第一种方法而不是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);
  }
});
这能做什么?一旦连接关闭,它将遍历所有未回复的游标,并在错误
连接关闭时为它们触发事件

测试用例:

items.find({ }).toArray(function(err, data) {
  if (!err) {
    console.log('Items found successfully');
  } else {
    console.log(err);
  }
});
db.close();
这将强制关闭数据库连接并触发您先前处理的
close
事件,并确保游标将被关闭

UPD:
我在GitHub上添加了一个问题:我们将看看他们对此有何评论。

我也遇到了同样的问题,并在谷歌上找到了这个页面。 但是你选择的答案并没有解决问题,它和你一样,这个。callBackStore不能使用

但是我试着把Mongo包起来,看起来效果不错

var MongoClient=require('mongodb')。MongoClient;
var mongo={};
mongo.init=函数(){
MongoClient.connect('mongodb://localhost:27017/testdb,函数(err,db){
如果(错误){
mongo.DB='';
}否则{
mongo.DB=DB;
}
db.on('close',function(){
mongo.DB='';
});
db.on('reconnect',function(){
mongo.DB=DB;
});
}
}
mongo.getdb=函数(回调){
if(mongo.DB){
回调(null,mongo.DB);
}否则{
回调('无法连接到数据库',null);
}
}

module.exports=mongo;
我正在用Hapi和Mongodb(不含mongoose)制作api。功能:

  • 仅当mongo db可用时才开始响应API请求
  • 如果mongo在循环期间死亡,则停止响应
  • 当mongo再次可用时重新启动
  • 为所有请求保持单一连接
  • 结合其他答案中的一些想法,我的方法如下:

    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});
    
        }
    };
    

    我正在将db连接导出到全局空间。这感觉不是最好的解决方案,但我有一些项目,其中db连接作为参数传递给所有模块,这更糟。也许应该有一些模块化的方法,在需要的地方导入db连接,但在我的情况下,我几乎在任何地方都需要它,我必须将其写入大多数文件中都有clude语句。此API与db没有连接,因此我认为这可能是最好的解决方案,即使我反对某些东西在全局空间中神奇地飞行。

    这是一个好问题:db.collection(上面的点#1)在db连接丢失时不会返回错误。collection.find(上面的点#2)最终将返回一个错误,但将在超过1分钟后返回。我在连接字符串中使用了connectionTimeoutMS和socketTimeoutMS设置,但行为没有改变。嘿@JesusRuiz,我让find调用运行了大约15-20分钟,我想是的,但它从未回叫过。我以前尝试过更改e超时属性,但正如您提到的,它们似乎没有任何效果!我不确定是否发现了b
    "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});
    
        }
    };