-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: 3.2.7
-
Component/s: None
-
Empty show more show less
This is basically a duplicate of JAVA-2987 but in the node driver. When the cursor tries to reconnect, it has an internal resumeToken value that it has acquired while iterating over earlier changes. If a startAtOperationTime was set when the cursor was originally created, it will also be sent and the server will respond with "Only one type of resume option is allowed, but multiple were found"
I've been reproducing this by starting a node process that watches a collection with a short socket timeout value, backgrounding the process so the cursor gets disconnected and then foregrounding the process again.
PR to fix the issue can be [found here|https://github.com/mongodb/node-mongodb-native/pull/2036]
Error:
Error { MongoError: Only one type of resume option is allowed, but multiple were found. at Connection.<anonymous> (/repro/node_modules/mongodb-core/lib/connection/pool.js:443:61) at emitTwo (events.js:126:13) at Connection.emit (events.js:214:7) at processMessage (/repro/node_modules/mongodb-core/lib/connection/connection.js:364:10) at Socket.<anonymous> (/repro/node_modules/mongodb-core/lib/connection/connection.js:533:15) at emitOne (events.js:116:13) at Socket.emit (events.js:211:7) at addChunk (_stream_readable.js:263:12) at readableAddChunk (_stream_readable.js:250:11) at Socket.Readable.push (_stream_readable.js:208:10) operationTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1560950316 }, ok: 0, errmsg: 'Only one type of resume option is allowed, but multiple were found.', code: 40674, codeName: 'Location40674', '$clusterTime': { clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1560950316 }, signature: { hash: [Object], keyId: 0 } }, name: 'MongoError', [Symbol(mongoErrorContextSymbol)]: {} }
Sample code (using node 8.13.0, driver 3.2.7 and mongo 4.10.0):
'use strict'; const { MongoClient, Timestamp } = require('mongodb'); function getCollection(database, collectionName) { return new Promise((resolve, reject) => { database.collection(collectionName, { strict: true }, (err, collection) => { if(err) { reject(err); } else { resolve(collection); } }); }); } (async () => { const mongoOptions = { socketTimeoutMS: 5000, useNewUrlParser: true }; const client = await MongoClient.connect('mongodb://mongo1,mongo2,mongo3/myTestDatabase?replicaSet=rs0', mongoOptions); const database = client.db('myTestDatabase'); const collection = await getCollection(database, 'myTestCollection'); const changeStreamCursor = collection.watch( [{ $match: { operationType: { $in: ['insert', 'update', 'replace', 'delete'] } } }], { fullDocument: 'updateLookup', startAtOperationTime: new Timestamp(0, (Date.now() / 1000) | 0), } ); changeStreamCursor.on('end', () => { console.error('End o\' cursor'); }); changeStreamCursor.on('close', () => { console.warn('Cursor closed!'); }); changeStreamCursor.on('error', (error) => { console.error('Error', error); }); changeStreamCursor.on('change', (event) => { console.log('Event: ', event); }); })();