Skip to content

Commit

Permalink
feat(index+connection): support setting global and connection-level `…
Browse files Browse the repository at this point in the history
…maxTimeMS`

Fix #4066
  • Loading branch information
vkarpov15 committed Jun 7, 2019
1 parent 8ec3dfb commit ec133c4
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/aggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const AggregationCursor = require('./cursor/AggregationCursor');
const Query = require('./query');
const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
const util = require('util');
const utils = require('./utils');
const read = Query.prototype.read;
Expand Down Expand Up @@ -932,6 +933,8 @@ Aggregate.prototype.exec = function(callback) {
const pipeline = this._pipeline;
const collection = this._model.collection;

applyGlobalMaxTimeMS(this.options, model);

if (this.options && this.options.cursor) {
return new AggregationCursor(this);
}
Expand Down
42 changes: 42 additions & 0 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,48 @@ Object.defineProperty(Connection.prototype, 'readyState', {
}
});

/**
* Gets the value of the option `key`. Equivalent to `conn.options[key]`
*
* ####Example:
*
* conn.get('test'); // returns the 'test' value
*
* @param {String} key
* @method get
* @api public
*/

Connection.prototype.get = function(key) {
return get(this.options, key);
};

/**
* Sets the value of the option `key`. Equivalent to `conn.options[key] = val`
*
* Supported options include:
*
* - `maxTimeMS`: Set [`maxTimeMS`](/docs/api.html#query_Query-maxTimeMS) for all queries on this connection.
* - `useFindAndModify`: Set to `false` to work around the [`findAndModify()` deprecation warning](/docs/deprecations.html#-findandmodify-)
*
* ####Example:
*
* conn.set('test', 'foo');
* conn.get('test'); // 'foo'
* conn.options.test; // 'foo'
*
* @param {String} key
* @param {Any} val
* @method set
* @api public
*/

Connection.prototype.set = function(key, val) {
this.options = this.options || {};
this.options[key] = val;
return val;
};

/**
* A hash of the collections associated with this connection
*
Expand Down
15 changes: 15 additions & 0 deletions lib/helpers/query/applyGlobalMaxTimeMS.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

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

module.exports = function applyGlobalMaxTimeMS(options, model) {
if (utils.hasUserDefinedProperty(options, 'maxTimeMS')) {
return;
}

if (utils.hasUserDefinedProperty(model.db.options, 'maxTimeMS')) {
options.maxTimeMS = model.db.options.maxTimeMS;
} else if (utils.hasUserDefinedProperty(model.base.options, 'maxTimeMS')) {
options.maxTimeMS = model.base.options.maxTimeMS;
}
};
5 changes: 5 additions & 0 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const MongooseError = require('./error/mongooseError');
const ObjectParameterError = require('./error/objectParameter');
const QueryCursor = require('./cursor/QueryCursor');
const ReadPreference = require('./driver').get().ReadPreference;
const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
const cast = require('./cast');
const castArrayFilters = require('./helpers/update/castArrayFilters');
Expand Down Expand Up @@ -1823,6 +1824,8 @@ Query.prototype._find = wrapThunk(function(callback) {
const _this = this;
const userProvidedFields = _this._userProvidedFields || {};

applyGlobalMaxTimeMS(this.options, this.model);

// Separate options to pass down to `completeMany()` in case we need to
// set a session on the document
const completeManyOptions = Object.assign({}, {
Expand Down Expand Up @@ -2042,6 +2045,8 @@ Query.prototype._findOne = wrapThunk(function(callback) {
this._applyPaths();
this._fields = this._castFields(this._fields);

applyGlobalMaxTimeMS(this.options, this.model);

// don't pass in the conditions because we already merged them in
Query.base.findOne.call(this, {}, (err, doc) => {
if (err) {
Expand Down
32 changes: 32 additions & 0 deletions test/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3396,6 +3396,38 @@ describe('Query', function() {
});
});

it('connection-level maxTimeMS() (gh-4066)', function() {
db.options = db.options || {};
db.options.maxTimeMS = 10;
const Model = db.model('gh4066_conn', new Schema({}));

return co(function*() {
yield Model.create({});

const res = yield Model.find({ $where: 'sleep(250) || true' }).
then(() => null, err => err);
assert.ok(res);
assert.ok(res.message.indexOf('time limit') !== -1, res.message);
delete db.options.maxTimeMS;
});
});

it('mongoose-level maxTimeMS() (gh-4066)', function() {
db.base.options = db.base.options || {};
db.base.options.maxTimeMS = 10;
const Model = db.model('gh4066_global', new Schema({}));

return co(function*() {
yield Model.create({});

const res = yield Model.find({ $where: 'sleep(250) || true' }).
then(() => null, err => err);
assert.ok(res);
assert.ok(res.message.indexOf('time limit') !== -1, res.message);
delete db.options.maxTimeMS;
});
});

it('throws error with updateOne() and overwrite (gh-7475)', function() {
const Model = db.model('gh7475', new Schema({ name: String }));

Expand Down

0 comments on commit ec133c4

Please sign in to comment.