Skip to content

Add support for maxTimeMS mongoOption #3018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions spec/MongoStorageAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,43 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
});

it('find succeeds when query is within maxTimeMS', (done) => {
const maxTimeMS = 250;
let adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { maxTimeMS },
});
adapter.createObject('Foo', { fields: {} }, { objectId: 'abcde' })
.then(() => adapter._rawFind('Foo', { '$where': `sleep(${maxTimeMS / 2})` }))
.then(
() => done(),
(err) => {
done.fail(`maxTimeMS should not affect fast queries ${err}`);
}
);
})

it('find fails when query exceeds maxTimeMS', (done) => {
const maxTimeMS = 250;
let adapter = new MongoStorageAdapter({
uri: databaseURI,
mongoOptions: { maxTimeMS },
});
adapter.createObject('Foo', { fields: {} }, { objectId: 'abcde' })
.then(() => adapter._rawFind('Foo', { '$where': `sleep(${maxTimeMS * 2})` }))
.then(
() => {
done.fail('Find succeeded despite taking too long!');
},
(err) => {
expect(err.name).toEqual('MongoError');
expect(err.code).toEqual(50);
expect(err.message).toEqual('operation exceeded time limit');
done();
}
);
});

it('stores pointers with a _p_ prefix', (done) => {
let obj = {
objectId: 'bar',
Expand Down
19 changes: 13 additions & 6 deletions src/Adapters/Storage/Mongo/MongoCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export default class MongoCollection {
// none, then build the geoindex.
// This could be improved a lot but it's not clear if that's a good
// idea. Or even if this behavior is a good idea.
find(query, { skip, limit, sort, keys } = {}) {
return this._rawFind(query, { skip, limit, sort, keys })
find(query, { skip, limit, sort, keys, maxTimeMS } = {}) {
return this._rawFind(query, { skip, limit, sort, keys, maxTimeMS })
.catch(error => {
// Check for "no geoindex" error
if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) {
Expand All @@ -30,22 +30,29 @@ export default class MongoCollection {
index[key] = '2d';
return this._mongoCollection.createIndex(index)
// Retry, but just once.
.then(() => this._rawFind(query, { skip, limit, sort, keys }));
.then(() => this._rawFind(query, { skip, limit, sort, keys, maxTimeMS }));
});
}

_rawFind(query, { skip, limit, sort, keys } = {}) {
_rawFind(query, { skip, limit, sort, keys, maxTimeMS } = {}) {
let findOperation = this._mongoCollection
.find(query, { skip, limit, sort })

if (keys) {
findOperation = findOperation.project(keys);
}

if (maxTimeMS) {
findOperation = findOperation.maxTimeMS(maxTimeMS);
}

return findOperation.toArray();
}

count(query, { skip, limit, sort } = {}) {
return this._mongoCollection.count(query, { skip, limit, sort });
count(query, { skip, limit, sort, maxTimeMS } = {}) {
let countOperation = this._mongoCollection.count(query, { skip, limit, sort, maxTimeMS });

return countOperation;
}

insertOne(object) {
Expand Down
21 changes: 17 additions & 4 deletions src/Adapters/Storage/Mongo/MongoStorageAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ export class MongoStorageAdapter {
this._uri = uri;
this._collectionPrefix = collectionPrefix;
this._mongoOptions = mongoOptions;

// MaxTimeMS is not a global MongoDB client option, it is applied per operation.
this._maxTimeMS = mongoOptions.maxTimeMS;
}

connect() {
Expand Down Expand Up @@ -329,7 +332,13 @@ export class MongoStorageAdapter {
return memo;
}, {});
return this._adaptiveCollection(className)
.then(collection => collection.find(mongoWhere, { skip, limit, sort: mongoSort, keys: mongoKeys }))
.then(collection => collection.find(mongoWhere, {
skip,
limit,
sort: mongoSort,
keys: mongoKeys,
maxTimeMS: this._maxTimeMS,
}))
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)))
}

Expand Down Expand Up @@ -358,14 +367,18 @@ export class MongoStorageAdapter {

// Used in tests
_rawFind(className, query) {
return this._adaptiveCollection(className).then(collection => collection.find(query));
return this._adaptiveCollection(className).then(collection => collection.find(query, {
maxTimeMS: this._maxTimeMS,
}));
}

// Executs a count.
// Executes a count.
count(className, schema, query) {
schema = convertParseSchemaToMongoSchema(schema);
return this._adaptiveCollection(className)
.then(collection => collection.count(transformWhere(className, query, schema)));
.then(collection => collection.count(transformWhere(className, query, schema), {
maxTimeMS: this._maxTimeMS,
}));
}

performInitialization() {
Expand Down