I am using Mongoose with a very large Mongo database, and I want costly queries like MySet.find({})
to time out after 10 seconds.
I\'ve tried setting a
You can do this with the Query#maxTime method.
So in your case, you would call it as:
MySet.find({}).maxTime(10000).exec(function(err, doc) { ... });
You can confirm it's correctly setting the maxTimeMS
option by enabling Mongoose debugging via mongoose.set('debug', true);
and then you'll see console output for this query that looks like:
Mongoose: myset.find({}) { maxTimeMS: 10000, safe: true, fields: {} }
I think this should work.
db.mycoll.find().maxTimeMS(50)
MySet.find({ $query: { /*Query here*/ }, $maxTimeMS: 10000 });
You can test with this query :
MySet.find({ $query: {"$where": "sleep(100) || true"}, $maxTimeMS: 10000 });
You can use Query modifiers
And especialy this one : $maxTimeMS
Be careful : this operator is deprecated in mongo Shell since v3.2
I finally got it working. First I prevent the server from crashing when the socket (i.e. a query) times out:
//don't crash the server if a query times out
mongoose.connection.on('error', function() {});
Then, every time I want to query the database, I disconnect from and reconnect to the database, setting socketTimeoutMS to 10000:
mongoose.disconnect();
mongoose.connect('mongodb://localhost/my_db', {
server: {socketOptions: {socketTimeoutMS: 10000}}
});
MySet.find({}, function(err, doc) {});
This cuts off the query after precisely 10 seconds of execution.
This is the pattern I have started to use a lot.
// Default time out timeout in ms
const DEFAULT_TIME_OUT = 500;
// Default timeout message
const DEFAULT_MESSAGE = `Timeout fetching data(${DEFAULT_TIME_OUT}ms)`;
// 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);
});
});
};
This way I have a default timeout applied to most requests but if I need to adjust on an per call basis then I can. Or I can be made aware of areas that need better indexing.