【问题标题】:How to ensure Node.js keeps running after MonogDB connection drops?如何确保 Node.js 在 MongoDB 连接断开后继续运行?
【发布时间】:2014-01-08 11:57:05
【问题描述】:

我在 Express 中有一个错误处理中间件,它试图捕获所有传入的错误:

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.status(500);
  res.render('500.jade');
});

但由于某种原因,每当我关闭 mongod 进程时,我的应用程序就会崩溃并显示以下堆栈跟踪:

Error: failed to connect to [localhost:27017]
    at null.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74)
    at EventEmitter.emit (events.js:106:17)
    at null.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15)
    at EventEmitter.emit (events.js:98:17)
    at Socket.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10)
    at Socket.EventEmitter.emit (events.js:95:17)
    at net.js:441:14
    at process._tickCallback (node.js:415:13)

Process finished with exit code 8

我曾尝试使用以下配置,但对我没有帮助:

var options = {
  server:{
    auto_reconnect: true,
      poolSize: 10,
      socketOptions:{
      keepAlive: 1
    }
  },
  db: {
    numberOfRetries: 10,
    retryMiliSeconds: 1000
  }
}

mongoose.connect(config.db, options);

您可能想知道“如果您的应用程序在没有数据库连接的情况下基本上不再运行,您为什么希望它运行?”。我不希望它崩溃并重新启动。 Supervisor 和 Forever 模块似乎在尝试一定次数后停止尝试重新连接,从而使您的应用程序处于崩溃状态。

理想情况下,当 MongoDB 崩溃时,我想向用户显示 500.jade 错误页面,同时服务器应该每 10 秒尝试重新连接到数据库。重新连接后,恢复所有正常操作。

编辑:下面发布的所有解决方案都对我有用,但域除外。

【问题讨论】:

    标签: node.js mongodb error-handling express mongoose


    【解决方案1】:

    这就是我处理 Mongo 失败的方法 - 将其添加为中间件。它还会尝试重新连接。

    // Handler in case Mongo  goes down
    app.use(function(req, res, next) {
      // We lost connection!
      if (1 !== mongoose.connection.readyState) {
    
        // Reconnect if we can
        mongoose.connect(config.db, options);
        res.status(503);
        throw new Error('Mongo not available');
      }
      next();
    
    });
    

    假设您在某个地方有一个标准的 50x 错误处理程序,可以向用户显示一个漂亮的页面。

    重新连接是为了下一次用户/页面加载以检查它是否已备份。很好用。

    【讨论】:

      【解决方案2】:

      尝试在domain 中初始化数据库,这样可以在不崩溃的情况下捕获错误

      var d = require('domain').create();
      
      d.on('error', function(er) {
          console.log('Oh no, something wrong with DB');
      });
      
      d.run(function() {
          mongoose.connect(config.db, options);
      });
      

      当发生崩溃时让服务器重新启动通常是个好主意,但由于您已经意识到这一点并希望避免这种情况,因此将任何失败的东西包装在域中就是这样做的方法。

      【讨论】:

      • 太棒了,我以前从未使用过 Node.js 域。今天学到了一些新东西;)。漂亮而优雅的解决方案。
      • @TwilightPonyInc. - 不久前添加的域,并且仍然被认为有些不稳定,但是我已经在生产中使用与 Cassandra 类似的东西作为 DB 一段时间了,并且从未遇到过问题,如果 DB 失败节点继续运行,当数据库再次可用时,就像什么都没发生过一样,我到处寻找泄漏,对我来说似乎很好。我还没有真正用Mongo尝试过,但原则上应该是一样的。
      • 只是不要开始在域中包装内部节点进程,因为这实际上可能导致问题和严重的泄漏。
      • 我不推荐包含任何 Mongoose 内容的域 - 您必须将所有查询都包含在其中。等待 Mongoose 支持。
      • 不会对域中的任何数据库或其他任何东西提供特殊支持,因为域只是一种捕获任何错误的方法,甚至是致命的节点错误,而不会导致节点崩溃。因此,应谨慎使用域,因为如果节点未重新启动,某些错误可能会导致意外行为。一般来说,数据库错误在 Node 中不是致命的,根据我的经验,如果不重新启动 Node 也不会导致问题,因此它们是为什么要添加域的完美示例;包装可能失败的代码,以免在失败期间使整个 Node 进程崩溃。
      【解决方案3】:

      当连接丢失时,MongoDB 驱动程序会发出一个“关闭”事件。您可以点击此事件并将数据库标记为不可用并基于此编写任何逻辑。

      db.on('close', function() {
        // handle the disconnect
        dbAvailable = false;
      });
      

      如果您有兴趣,我有一个小型 NPM 模块可以处理这个问题:https://npmjs.org/package/mongoconnect

      【讨论】:

      • 我可以通过简单的console.log() 成功捕获此事件,但大约 1 秒后,服务器因throw er; // Unhandled 'error' event 而崩溃。我在这里做错了吗? (使用最新版本的 Express 和 Mongoose)。类似于:stackoverflow.com/questions/17809285/…
      猜你喜欢
      • 1970-01-01
      • 2021-12-23
      • 2021-02-12
      • 1970-01-01
      • 2018-10-16
      • 2018-07-28
      • 1970-01-01
      • 2016-08-23
      • 2013-04-30
      相关资源
      最近更新 更多