Incorrect diagnostics when trying to execute transaction on a deployment without tx number support

XMLWordPrintableJSON

    • Type: Improvement
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: 3.6.0
    • Component/s: None
    • None
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      I am following the example in https://docs.mongodb.com/manual/core/transactions/ with a deployment using 4.0 replica set with mmapv1 which does not support transactions.

      const { MongoClient } = require("mongodb");
      
      const uri = "mongodb://localhost:14071/?retrywrites=false&directconnection=false"
      
      const client = new MongoClient(uri,{useUnifiedTopology:true});
      
      async function run() {
        await client.connect();
      
       // Prereq: Create collections.
      
        await client.db('mydb1').collection('foo').insertOne({ abc: 0 }, { w: 'majority' });
      
        await client.db('mydb2').collection('bar').insertOne({ xyz: 0 }, { w: 'majority' });
      
        // Step 1: Start a Client Session
        const session = client.startSession();
      
        // Step 2: Optional. Define options to use for the transaction
        const transactionOptions = {
          readPreference: 'primary',
          readConcern: { level: 'local' },
          writeConcern: { w: 'majority' }
        };
      
        // Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error)
        // Note: The callback for withTransaction MUST be async and/or return a Promise.
        try {
          await session.withTransaction(async () => {
            const coll1 = client.db('mydb1').collection('foo');
            const coll2 = client.db('mydb2').collection('bar');
      
            // Important:: You must pass the session to the operations
      
            await coll1.insertOne({ abc: 1 }, { session });
            await coll2.insertOne({ xyz: 999 }, { session });
          }, transactionOptions);
        } finally {
          await session.endSession();
          await client.close();
        }
      }
      run().catch(console.dir);
      

      I get the following diagnostics:

      serene% node test.js
      MongoError: This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.
          at getMMAPError (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/core/topologies/shared.js:413:18)
          at handler (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/core/sdam/topology.js:944:15)
          at /home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/connection_pool.js:354:13
          at handleOperationResult (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/core/sdam/server.js:558:5)
          at commandResponseHandler (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/core/wireprotocol/command.js:115:25)
          at MessageStream.messageHandler (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/connection.js:266:11)
          at MessageStream.emit (events.js:315:20)
          at processIncomingData (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
          at MessageStream._write (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
          at doWrite (_stream_writable.js:403:12) {
        originalError: MongoError: Transaction numbers are only allowed on storage engines that support document-level locking
            at MessageStream.messageHandler (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/connection.js:266:20)
            at MessageStream.emit (events.js:315:20)
            at processIncomingData (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
            at MessageStream._write (/home/w/apps/tests/retryable-writes-node/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
            at doWrite (_stream_writable.js:403:12)
            at writeOrBuffer (_stream_writable.js:387:5)
            at MessageStream.Writable.write (_stream_writable.js:318:11)
            at Socket.ondata (_stream_readable.js:717:22)
            at Socket.emit (events.js:315:20)
            at addChunk (_stream_readable.js:295:12) {
          operationTime: Timestamp { _bsontype: 'Timestamp', low_: 2, high_: 1596646405 },
          ok: 0,
          code: 20,
          codeName: 'IllegalOperation',
          '$clusterTime': { clusterTime: [Timestamp], signature: [Object] }
        }
      }
      

      Note that the error message instructs me to add retrywrites=false to the connection string, which I have already done. This is a very confusing situation to deal with as a user of the driver.

      The Ruby driver provides the "Please add retryWrites=false to your connection string." instruction when issuing inserts and retrywrites=false is not set (in which case setting retrywrites=false would in fact fix the insert not working), but not when issuing transactions where it doesn't help.

      I expect the node driver to:

      • Not suggest to users that they add retrywrites=false to their connection string when this option is already requested by the users.
      • Not suggest to users that they add retrywrites=false when this will not make the operation succeed, specifically when they are attempting transactions.

      Test code:
      https://github.com/p-mongo/tests/tree/master/retryable-writes-node
      https://github.com/p-mongo/tests/tree/master/retryable-writes-ruby

            Assignee:
            Unassigned
            Reporter:
            Oleg Pudeyev (Inactive)
            None
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: