Uploaded image for project: 'Node.js Driver'
  1. Node.js Driver
  2. NODE-6190

Using Promise.all inside transactions errors with "Cannot pin multiple connections to the same session" on serverless instance

    • 2
    • Not Needed
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      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);
        });
      

        There are no Sub-Tasks for this issue.

            Assignee:
            warren.james@mongodb.com Warren James
            Reporter:
            val@karpov.io Valeri Karpov
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: