猫鼬在未指定的时间段后停止响应

时间:2016-03-11 23:53:12

标签: node.js mongodb azure mongoose

自从我开始开发我的项目(12个月前!)之后,我一直在解决这个问题,总是假设在我准备发布之前我会找到答案...不幸的是,那不是情况下!

基本上,我有一个相当简单的node.js服务器在Azure上运行,使用mongoose连接到MongoLab(现在是MLab)数据库。

连接代码如下所示:

// Connect to DB
//mongoose.set('debug', true);
mongoose.connect(envConfig.app.db, {
    server: {
        auto_reconnect: true,
        socketOptions: {
            keepAlive: 1,
            connectTimeoutMS: 30000,
            socketTimeoutMS : 30000,
        }
    },
    replset: {
        auto_reconnect: true,
        socketOptions: {
            keepAlive: 1,
            connectTimeoutMS: 30000,
            socketTimeoutMS : 30000,
        }
    }
}, function (err) {
    if (err) winstonLogger.error(err);
});
mongoose.connection.on('connecting', function () {
    console.log('Connecting to MongoDB...');
});
mongoose.connection.on('connected', function () {
    console.log('MongoDB connected!');
});
mongoose.connection.on('open', function () {
    console.log('MongoDB connection opened!');
});
mongoose.connection.on('error', function (err) {
    console.error('Error in MongoDb connection: ' + err.stack);
    winstonLogger.error(err);
    mongoose.disconnect();
});
mongoose.connection.on('disconnected', function () {
    winstonLogger.error('MongoDB disconnected!');
    mongoose.connect(envConfig.app.db, {
        server: {
            auto_reconnect: true,
            socketOptions: {
                keepAlive: 1,
                connectTimeoutMS: 30000,
                socketTimeoutMS : 30000,
            }
        },
        replset: {
            auto_reconnect: true,
            socketOptions: {
                keepAlive: 1,
                connectTimeoutMS: 30000,
                socketTimeoutMS : 30000,
            }
        }
    });
});
mongoose.connection.on('reconnected', function () {
    console.log('MongoDB reconnected!');
});
mongoose.connection.on('close', function () {
    console.log('MongoDB closed');
});

您看到的所有额外超时选项等都是我尝试解决此问题的一部分(无济于事)。

这是一个典型的请求:

AccessToken.findOne({ token: token })
            .maxTime(10000)
            .exec(function (err, accessToken) {
                // If I even got to here I would be happy
                if (err) return done(err);
                // If I could consistently get to here, my project would be finished and I would enjoy being alive again
            });

所以,当我启动我的服务器时,一切都很好。并且它保持良好的工作...有时几天,有时几小时,有时几分钟。但是,在某些时候,请求会触及此代码,它只会...挂起。没有超时,没有错误。只是虚无...我没有在任何日志中找到任何证据来证明发生了什么。我的快速记录器终于放弃了,我得到了类似的东西:

POST /api/auth/verify - - ms - -

所以在这一点上,我唯一的选择是重新启动服务器,因为我无法获得数据库请求来完成(或超时,或显示错误)的爱情和金钱。

我已经在互联网上搜索了一年希望得到一个解决方案,但我所尝试的一切都导致......没有......同样的结果。我甚至尝试在Azure上运行我自己的副本集而不是使用MongoLab。同样的问题。我唯一的想法是,这是一个没有明显解决方案的Azure问题,但我真的不热衷于寻找另一个主机。话虽这么说,我不明白为什么Mongoose请求不会超时或显示任何错误,即使我设置了maxTime ......

以下是MongoLab关于我认为可能出现的问题的一些信息: http://docs.mlab.com/connecting/#known-issues, 但正如你所看到的,我已经尝试过他们所建议的一切,而且还有更多,但没有成功。

我真的很茫然,整个情况同时让人头脑麻木,令人心碎,令人难以置信的真气。

如果有人有任何想法,我会永远爱你...

提前谢谢!

路加福音

3 个答案:

答案 0 :(得分:4)

好的,所以我暂时没有问题。我对连接设置进行了很多小的更改,但我认为最大的影响是显式设置ha(高可用性)和haInterval replset选项,或者可能将连接代码移动到我的app.js的最后

这是最终连接代码的样子:

// Connect to DB
var connectionOptions = {
    replset: {
        socketOptions: {
            connectTimeoutMS: 300000, // 5 minutes
            keepAlive: 120
        },
        ha: true, // Make sure the high availability checks are on
        haInterval: 10000, // Run every 10 seconds
    }
};
//mongoose.set('debug', true);
mongoose.connect(envConfig.app.db, connectionOptions, function (err) {
    if (err) winstonLogger.error(err);
});
mongoose.connection.on('connecting', function () {
    console.log('Connecting to MongoDB...');
});
mongoose.connection.on('connected', function () {
    console.log('MongoDB connected!');
});
mongoose.connection.on('open', function () {
    console.log('MongoDB connection opened!');
});
mongoose.connection.on('error', function (err) {
    winstonLogger.error(err);
    mongoose.disconnect();
});
mongoose.connection.on('disconnected', function () {
    winstonLogger.error('MongoDB disconnected!');
    mongoose.connect(envConfig.app.db, connectionOptions, function (err) {
        if (err) winstonLogger.error(err);
    });
});
mongoose.connection.on('reconnected', function () {
    console.log('MongoDB reconnected!');
});
mongoose.connection.on('close', function () {
    winstonLogger.error('MongoDB closed');
});
if (mongoose.connection.db.serverConfig.s.replset) {
    mongoose.connection.db.serverConfig.s.replset.on('ha', function(type, data) {
        console.log('replset ha ' + type);
    });
    mongoose.connection.db.serverConfig.s.replset.on('timeout', function () {
        winstonLogger.error('MongoDB timeout');
    });
}

我还打开了Azure WebApp的AlwaysOn选项(它似乎没有太大影响,但我现在没有关闭它,因为它正在工作!)。

似乎问题与故障转移后没有重新连接有关,但我无法100%确定地说。

希望这能帮助遇到同样问题的其他人...并且希望我没有跳过枪只让它在几天内再次停止工作(如果发生这种情况我会回来的!)

感谢所有提出建议的人,我非常感激:)

答案 1 :(得分:2)

这听起来很像我几个月来使用相同设置的问题(Azure上的NodeJ,Mongoose,MongoLab副本集)。肯定是“同时脑筋麻木,令人心碎,令人难以置信的真气”。经过几个小时的挫折后,我终于在几个月前解决了这个问题......

我发现它是由副本集故障转移触发的。这是通过在Azure上使用测试服务器并在MongoLab上设置测试副本以及在Mongolab上手动触发故障转移来验证的(我无法通过在本地运行NodeJs服务器和MongoDB实例来重现,因为问题与连接时间有关)。 / p>

故障转移后应该帮助Mongoose连接到辅助服务器的高可用性检查未正确运行。由于某种竞争条件,如果服务器在初始化Mongoose连接后需要一段时间启动,则启动检查的回调将在mongodb-core中失败。

我最终做的是尽可能晚地将Mongoose连接移动到服务器启动过程中。它曾经是一个非常大的文件缩小任务,这可能是问题。

希望这有帮助!

我的猫鼬设置:

// Options
mongooseOptions.replset = {
  ha: true, // Make sure the high availability checks are on
  haInterval: 5000, // Run every 5 seconds
  socketOptions : {
    ... // nothing special here
  }
}

mongoose.connect(mongodb_uri, mongooseOptions);

// Make sure the high availability checks are occuring
// Should see "replset ha start" "replset ha end" pairs every 5 secs
// Well, hopefully.
if (mongoose.connection.db.serverConfig.s.replset) {
  mongoose.connection.db.serverConfig.s.replset.on('ha', function(type, data) {
    console.log('replset ha ' + type);
  })
}

答案 2 :(得分:0)

根据我的经验,我建议您可以在Mlab上ping mongodb,以确保在您的webapp挂起时是否用完了mongo连接。

我认为你可以尝试为mongoose连接添加连接池选项,正如@BlakesSeven所说。请参阅Mongoose guide topic ConnectionsConnection pools部分以配置池大小。