如何在Mongoose查询上设置超时?

我正在使用一个非常大的Mongo数据库Mongoose,我想要像MySet.find({})昂贵的查询10秒后超时。

我已经尝试在我的连接上设置套接字超时,但如果超时超时服务器崩溃:

 var options = {server: {socketOptions: {socketTimeoutMS: 10000}}}; var conn = mongoose.connect('mongodb://localhost/my_db', options); 

我已经尝试将maxTimeMS选项传递给find函数,但是根本没有任何效果:

 MySet.find({}, {}, {timeout: true, maxTimeMS: 10000}, function(err, doc) {}); 

有任何想法吗?

你可以使用Query#maxTime方法来做到这一点,这个方法在Mongoose本身没有logging,但它是Mongoose为其stream畅的查询接口使用的mquery库的一部分。

所以在你的情况下,你可以这样称呼它:

 MySet.find({}).maxTime(10000).exec(function(err, doc) { ... }); 

您可以通过maxTimeMS mongoose.set('debug', true);启用Mongoosedebugging来确认是否正确设置了maxTimeMS选项mongoose.set('debug', true); 然后你会看到这个查询的控制台输出,如下所示:

 Mongoose: myset.find({}) { maxTimeMS: 10000, safe: true, fields: {} } 

我认为这应该工作。

db.mycoll.find()。maxTimeMS(50)

TL; DR:

 MySet.find({ $query: { /*Query here*/ }, $maxTimeMS: 10000 }); 

你可以用这个查询来testing:

 MySet.find({ $query: {"$where": "sleep(100) || true"}, $maxTimeMS: 10000 }); 

为什么它的作品:

您可以使用查询修饰符

特别是这个: $ maxTimeMS

注意 :这个操作符在v3.2以后在mongo Shell中被弃用了

这是我开始使用很多的模式。

 // Default time out timeout in ms const DEFAULT_TIME_OUT = 500; // Default timeout message const DEFAULT_MESSAGE = 'Timeout fetching data(${DEFAULT_TIME_OUT}ms)'; // Removed angled single quotes // Function that triggers a Promise's reject after a set amount of time function timeoutReject(reject, message, timeout) { setTimeout(function(){ // Reject the Promise if the time is reached reject(message || DEFAULT_MESSAGE); }, timeout || DEFAULT_TIME_OUT); }; function youAreNotAuthentic() { // Logic to validate user and request return boolean }; // Throw error if the user cannot access this data function youCantTouchThis() { throw new Error('You cannot access this data.'); }; // Function to request data function getDataById(_id) { // First check if this is authentic if (youAreNotAuthentic()) youCantTouchThis(); // Return a Promise return new Promise((resolve, reject) => { // Set a timeout to reject if we do not get a response in x time timeoutReject(reject, 'Custom Message', 300); // Could look like this to just use the defaults // timeoutReject(reject); // Query for the data Collection.findOne({ _id }).then(data => { // Resolve the Promise with the retrieved data resolve(data); }); }); }; 

这样,我有一个默认的超时适用于大多数请求,但如果我需要调整每个呼叫的基础上,那么我可以。 或者我可以意识到需要更好索引的领域。

我终于搞定了。 首先,当套接字(即查询)超时时,防止服务器崩溃:

 //don't crash the server if a query times out mongoose.connection.on('error', function() {}); 

然后,每次我要查询数据库,我断开连接并重新连接到数据库,将socketTimeoutMS设置为10000:

 mongoose.disconnect(); mongoose.connect('mongodb://localhost/my_db', { server: {socketOptions: {socketTimeoutMS: 10000}} }); MySet.find({}, function(err, doc) {}); 

这恰好在执行10秒后切断查询。