Mongo db with Monk:如果 db 关闭则错误捕获和处理

Mongo db with Monk: error catching and handling if db is down

我是 Mongo 的新手。我需要一个用于一个简单项目的数据库,并最终遵循了使用 Mongo 和 Monk 的教程,但我在理解如何处理错误时遇到了问题。

背景: 我在客户端有一个注册表。当用户单击按钮时,数据通过 AJAX 发送到控制器(经过验证,但现在不相关)将此类数据插入数据库并发回成功或错误。当数据库启动时,一切似乎都工作正常。

问题:如果我不启动数据库并尝试发送请求,则不会返回任何错误。什么也没有发生。在控制台上一段时间后,我得到:POST /members/addmember - - ms - -.

我认为在这种情况下应该向用户返回一些错误,那么我该怎么做呢?

post 请求如下(与教程中的差不多):

// app.js 

var db = monk('localhost:27017/dbname')
[...]
// I realize it might be not optimal here
app.use(function(req,res,next){ 
    req.db = db;
    next();
});

// members.js

router.post('/addmember', function(req, res) {
  var db = req.db;
  var collection = db.get('memberstest');
  collection.insert(req.body, function(err, result){
    res.json(
      (err === null) ? { msg: 'success' } : { msg: err }
    );
  });
});

如果数据库出现故障,我猜这个问题实际上比插入更早,那就是“db.get()”。那么如何检查 get 是否真的可以完成呢?我想鉴于节点的异步性质,try/catch 之类的东西在这里毫无意义。正确吗?

编辑:在 Neil 的回答和一些尝试之后,我将以下内容放在一起似乎可以完成这项工作。但是,鉴于我对此缺乏信心,如果下面的代码因为有意义或偶然而有效,我将不胜感激。我添加了 bufferMaxEntries: 0 选项并修改了控制器如下。在 ajax 回调中,我现在只有一个警报,显示抛出的错误消息(如果有)。

router.post('/addmember', async (req,res) => {

    try {
      let db = req.db;
      let collection = db.get('memberstest');

      collection.insert(req.body, function(err, result){
      res.json(
        (err === null) ? { msg: 'success' } : { msg: err }
      );
    });

    await db.then(() => 1);

    } catch(e) {
      res.json({msg: e.message})
    }

});

好吧,您实际上可以在连接上设置 bufferMaxEntries 选项(在 Db 下记录,但不推荐使用该对象,在 "top level as demonstrated instead" 处使用),这实际上会停止 "queuing" 在实际不存在连接时向驱动程序请求。

作为一个最小的例子:

index.js

const express = require('express'),
      morgan = require('morgan'),
      db = require('monk')('localhost/test',{ bufferMaxEntries: 0 }),
      app = express();

const routes = require('./routes');

app.use(morgan('combined'));

app.use((req,res,next) => {
  req.db = db;
  next();
});

app.use('/', routes);

(async function() {

  try {

    await db.then(() => 1);

    let collection = db.get('test');
    await collection.remove({});

    await collection.insert(Array(5).fill(1).map((e,i) => ({ a: i+1 })));
    console.log('inserted test data');

    await app.listen(3000,'0.0.0.0');
    console.log('App waiting');

  } catch(e) {
    console.error(e);
  }

})();

routes.js

var router = require('express').Router();

router.get('/', async (req,res) => {
  try {
    let db = req.db,
        collection = db.get('test');

    let response = await collection.find();
    res.json(response);
  } catch(e) {
    res.status(500).json(e);
  }
});

module.exports = router;

所以我实际上是在等待数据库连接至少出现在 "start up" 此处,但实际上只是为了举例,因为我想插入一些数据以进行实际检索。这不是必需的,但基本概念是等待 Promise 解析:

await db.then(() => 1);

有点微不足道,对于您的实际代码来说并不是真正需要的。但我仍然认为这是一个很好的做法。

真正的测试是通过停止 mongod 或以其他方式使服务器无法访问然后发出请求来完成的。

由于我们将连接选项设置为{ bufferMaxEntries: 0 },这意味着当您尝试向数据库发出命令时立即,失败将是returned 如果没有实际连接存在。

当然,当数据库再次可用时,您不会收到错误,指令会正常进行。

没有该选项,默认是 "en-queue" 操作,直到连接被解析,然后 "buffer" 本质上是 "played"。

您可以通过 "stopping" mongod 守护程序和发出请求来模拟这个(就像我所做的那样)。然后 "starting" 守护进程和发出请求。它应该只是 return 捕获的错误响应。

NOTE: Not required, but in fact the whole purpose of async/await syntax is to make things like try..catch valid again, since you can actually scope as blocks rather than using Promise.catch() or err callback arguments to trap the errors. Same principles apply when either of those structures are actually in use though.