Node和Mongoose - 如果mongod在第一次尝试连接时没有运行,则不重新连接

时间:2016-04-24 19:02:17

标签: mongodb express mongoose

使用docker-composer,我发现了服务执行顺序的问题。主要问题发生在我的快递应用尝试连接到mongod但尚未准备好

首先运行nodejs应用程序而不是mongod (手动强制执行此情况),可以轻松复制问题。

我的应用使用mongoose并尝试建立与mongod的连接。由于 mongod未启动并正在运行,因此应用程序会抛出错误

$ nodemon server/app.js 
24 Apr 21:42:05 - [nodemon] v1.7.0
24 Apr 21:42:05 - [nodemon] to restart at any time, enter `rs`
24 Apr 21:42:05 - [nodemon] watching: *.*
24 Apr 21:42:05 - [nodemon] starting `node server/app.js`
Listening on port 8000
disconnected
connection error: { [MongoError: connect ECONNREFUSED] name: 'MongoError', message: 'connect ECONNREFUSED' }

稍后启动mongod似乎重新连接

24 Apr 21:51:28 - [nodemon] v1.7.0
24 Apr 21:51:28 - [nodemon] to restart at any time, enter `rs`
24 Apr 21:51:28 - [nodemon] watching: *.*
24 Apr 21:51:28 - [nodemon] starting `node server/app.js`
Listening on port 8000
disconnected
connection error: { [MongoError: connect ECONNREFUSED] name: 'MongoError', message: 'connect ECONNREFUSED' }
connected
reconnected

尽管如此,需要访问mongo的操作才会通过 ...都不会显示错误

enter image description here

这是使用mongoose连接到mongo的代码:

// Starting mongo
mongoose.connect(config.database, {
                                    server:{
                                            auto_reconnect:true,
                                            reconnectTries: 10,
                                            reconnectInterval: 5000,
                                    }
                                });

// Listening for connection
var mongo = {};
var db = mongoose.connection;
db.on('connected', console.error.bind(console, 'connected'));
db.on('error', console.error.bind(console, 'connection error:'));
db.on('close', console.error.bind(console, 'connection close.'));
db.once('open', function() {
    console.log("We are alive");
});
db.on('reconnected', function(){
    console.error('reconnected');   
});
db.on('disconnected', console.error.bind(console, 'disconnected'));

这是尝试从mongo获取数据但失败的路由。

router.post('/auth', function(req, res){

    User.findOne({name: req.body.name})
        .then(function(user){

            if(!user)
            {
                res.status(401).send({ success: false, message: 'Authentication failed. User not found.' });
            }
            ...

如何在mongo准备好之前从运行nodejs中恢复?

3 个答案:

答案 0 :(得分:1)

就我而言,我仅为猫鼬连接方法创建了单独的函数:

const connect = () => {
    mongoose.connect('mongodb://localhost:27017/myapp', {
        useNewUrlParser: true,
        reconnectTries: Number.MAX_VALUE,
        reconnectInterval: 500,
        poolSize: 10,
    });
};

我在同一时间称呼它。我还为error事件添加了事件处理程序:

mongoose.connection.on('error', (e) => {
    console.log('[MongoDB] Something went super wrong!', e);
    setTimeout(() => {
        connect();
    }, 10000);
});

如果由于MongoDB未运行而导致猫鼬连接失败,则会触发错误事件处理程序,并且setTimeout计划“自定义”重新连接。

希望有帮助。

答案 1 :(得分:0)

mongod准备好之前需要多长时间?因为看起来这是一个边缘案例问题,mongod可能需要几秒钟才能准备好;当连接mongoose时,它按预期提供请求。只是想了解为什么需要稍微延迟(可能只有几秒钟)才能解决?

但无论如何这是一个解决方案:

您可以设置一个快速中间件来检查mongoose是否准备好,如果没有则抛出错误:

app.use(function(req,res,next){
    if (mongoose.Connection.STATES.connected === mongoose.connection.readyState){
        next();
    } else {
        res.status(503).send({success:false, message: 'DB not ready' });
    }
});

这应该在注入路由器之前进行。

答案 2 :(得分:0)

我在Mongoose 5+上遇到了同样的问题。我可以通过使用设置超时创建重试功能来使此工作正常进行。

const mongoose = require('mongoose');

const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB,
  MONGO_DEBUG,
  MONGO_RECONNECT_TRIES,
  MONGO_RECONNECT_INTERVAL,
  MONGO_TIMEOUT_MS,
} = process.env;

if (MONGO_DEBUG) {
  console.log(`********* MongoDB DEBUG MODE *********`);
  mongoose.set('debug', true);
}

const DB_OPTIONS = {
  useNewUrlParser: true,
  reconnectTries: MONGO_RECONNECT_TRIES,
  reconnectInterval: MONGO_RECONNECT_INTERVAL,
  connectTimeoutMS: MONGO_TIMEOUT_MS,
};

const DB_URL = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

// Initialize conenction retry counter
let reconnectTriesAlready = 1;

// Connect to database with timeout and retry
const connectWithRetry = () => {
  mongoose.connect(DB_URL, DB_OPTIONS).then(() => {
    // Connected successfully
    console.log('********* MongoDB connected successfully *********');
    // Reset retry counter
    reconnectTriesAlready = 1;
  }).catch(err => {
    // Connection failed
    console.error(`********* ERROR: MongoDB connection failed ${err} *********`)
    // Compare retries made already to maximum retry count
    if (reconnectTriesAlready <= DB_OPTIONS.reconnectTries) {
      // Increment retry counter
      reconnectTriesAlready = reconnectTriesAlready + 1;
      // Reconnect retries made already has not exceeded maximum retry count
      console.log(`********* MongoDB connection retry after ${MONGO_RECONNECT_INTERVAL / 1000} seconds *********`)
      // Connection retry
      setTimeout(connectWithRetry, MONGO_RECONNECT_INTERVAL)
    } else {
      // Reconnect retries made already has exceeded maximum retry count
      console.error(`********* ERROR: MongoDB maximum connection retry attempts have been made already ${DB_OPTIONS.reconnectTries} stopping *********`)
    }
  })
}

connectWithRetry();