-
Type: Bug
-
Resolution: Works as Designed
-
Priority: Minor - P4
-
None
-
Affects Version/s: 6.6.2
-
Component/s: Serverless, Sessions, Transactions
Use Case
As a... developer
I want... to use Promise.all() to execute queries in parallel in a transaction against a serverless instance
So that... I can speed up my transactions
User Impact
- At least 1 user. Not a blocker.
Dependencies
- N/A
Unknowns
- N/A
Acceptance Criteria
Implementation Requirements
- Be able to execute Promise.all() within transaction against serverless instance
Testing Requirements
- functional test based on the following
const mongoose = require('mongoose'); //mongoose.connect('mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoose_test'); const userSchema = new mongoose.Schema({ name: String, }); void async function main() { console.log("Start"); await mongoose.connect('serverless url here'); const User = mongoose.model('User', userSchema); await User.create({ name: 'test' }); console.log('Inserted'); await mongoose.connection.transaction(async session => { const docs = await Promise.all([ User.findOne({}, null, { session }), User.findOne({}, null, { session }), ]); console.log(docs); }); console.log('Done'); }(); async function sleep(ms) { await new Promise(resolve => setTimeout(resolve, ms)); }
Documentation Requirements
- N/A
Follow Up Requirements
- N/A
My summary:
See https://github.com/Automattic/mongoose/issues/14603. Running the following Mongoose script against a serverless instance:
const mongoose = require('mongoose'); //mongoose.connect('mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoose_test'); const userSchema = new mongoose.Schema({ name: String, }); void async function main() { console.log("Start"); await mongoose.connect('serverless uri here'); const User = mongoose.model('User', userSchema); await User.create({ name: 'test' }); console.log('Inserted'); await mongoose.connection.transaction(async session => { const docs = await Promise.all([ User.findOne({}, null, { session }), User.findOne({}, null, { session }), ]); console.log(docs); }); console.log('Done'); }(); async function sleep(ms) { await new Promise(resolve => setTimeout(resolve, ms)); }
Results in the following error:
$ node gh-14603.js Start Inserted /home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/sessions.js:115 throw TypeError('Cannot pin multiple connections to the same session'); ^ TypeError: Cannot pin multiple connections to the same session at ClientSession.pin (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/sessions.js:115:19) at Server.command (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/sdam/server.js:154:30) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async FindOperation.execute (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/operations/find.js:33:16) at async executeOperation (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/operations/execute_operation.js:136:16) at async FindCursor._initialize (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/cursor/find_cursor.js:58:26) at async [kInit] (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/cursor/abstract_cursor.js:463:27) at async next (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/cursor/abstract_cursor.js:520:13) at async FindCursor.next (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/cursor/abstract_cursor.js:237:16) at async Collection.findOne (/home/val/Workspace/MongoDB/mongoose/node_modules/mongodb/lib/collection.js:275:21)
This seems to only happen against serverless instances. Works fine with local replica set.
Also, this only happens if the Promise.all() is the first async operation in the transaction. For example, the following works as expected:
await mongoose.connection.transaction(async session => { await User.findOne({}, null, { session }); const docs = await Promise.all([ User.findOne({}, null, { session }), User.findOne({}, null, { session }), ]); console.log(docs); });
As does the following:
await mongoose.connection.transaction(async session => { const docs = await Promise.all([ User.findOne({}, null, { session }), sleep(0).then(() => User.findOne({}, null, { session })), ]); console.log(docs); });