Skip to content
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

Transactions with Promise.all throwing TransientTransactionError #7311

Closed
adiliqbl opened this issue Dec 8, 2018 · 1 comment
Closed

Transactions with Promise.all throwing TransientTransactionError #7311

adiliqbl opened this issue Dec 8, 2018 · 1 comment

Comments

@adiliqbl
Copy link

adiliqbl commented Dec 8, 2018

Hi. I need help working with transactions and mongodb replica sets. I'm trying to run multi-document transactions. The query creates multiple Permissions which are then added as ref in Role and if query fails, the transaction is aborted.

What is the current behavior?
Initially roles are added and transaction fails at save({session}) and throws 'TransientTransactionError: Transaction 1 does not exist'. If I run script for the second time, no roles are inserted and database freezes on Permissions.create(permissions, {session}).

run-rs --mongod --dbpath "mongodb" --keep --number 2

 mongoose.connect('mongodb://localhost:27017, localhost:27018/Test?replicaSet=rs`');

 Role.collection.drop();
 Permissions.collection.drop();

 let permissions = [list];
 let session = null;
 
 console.log('Creating Roles');
 Permissions.createCollection() // Role is created automatically because of index
        .then(() => Promise.all(roleQueries));

role.validate()
        .then(() => Role.startSession())
        .then(_session => {
            session = _session;
            session.startTransaction();
            return Permissions.create(permissions, {session}) // freezes here
        })
        .then(() => {
            doc.permissions = permissions.map(val => val._id);
            return doc.save({session});
        })
        .then(async () => {
            await session.commitTransaction();
            session.endSession();
        })
        .catch(async error => {
            if (session) {
                await session.abortTransaction();
                session.endSession();
            }
            throw error;
        });

And here's the error log.

Dropped Permissions
Dropped Roles
Creating Roles

{ MongoError: Given transaction number 1 does not match any in-progress transactions.
    at /home/adil/WebstormProjects/jinnah-hospital/server/node_modules/mongodb-core/lib/connection/pool.js:581:63
    at authenticateStragglers (/home/adil/WebstormProjects/jinnah-hospital/server/node_modules/mongodb-core/lib/connection/pool.js:504:16)
    at Connection.messageHandler (/home/adil/WebstormProjects/jinnah-hospital/server/node_modules/mongodb-core/lib/connection/pool.js:540:5)
    at emitMessageHandler (/home/adil/WebstormProjects/jinnah-hospital/server/node_modules/mongodb-core/lib/connection/connection.js:310:10)
    at Socket.<anonymous> (/home/adil/WebstormProjects/jinnah-hospital/server/node_modules/mongodb-core/lib/connection/connection.js:489:15)
    at Socket.emit (events.js:182:13)
    at addChunk (_stream_readable.js:283:12)
    at readableAddChunk (_stream_readable.js:264:11)
    at Socket.Readable.push (_stream_readable.js:219:10)
    at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
  errorLabels: [ 'TransientTransactionError' ],
  operationTime:
   Timestamp { _bsontype: 'Timestamp', low_: 12, high_: 1544265326 },
  ok: 0,
  errmsg:
   'Given transaction number 1 does not match any in-progress transactions.',
  code: 251,
  codeName: 'NoSuchTransaction',
  '$clusterTime':
   { clusterTime:
      Timestamp { _bsontype: 'Timestamp', low_: 12, high_: 1544265326 },
     signature: { hash: [Binary], keyId: 0 } },
  name: 'MongoError',
  [Symbol(mongoErrorContextSymbol)]: {} }

Dropped Permissions
Dropped Roles
Creating Roles
> freezes for a minute here

{ MongoError: Transaction 1 has been aborted.
  at server/node_modules/mongodb-core/lib/connection/pool.js:581:63
  at authenticateStragglers (/server/node_modules/mongodb-core/lib/connection/pool.js:504:16)
  at Connection.messageHandler (server/node_modules/mongodb-core/lib/connection/pool.js:540:5)
  at emitMessageHandler (server/node_modules/mongodb-core/lib/connection/connection.js:310:10)
  at Socket.<anonymous> (server/node_modules/mongodb-core/lib/connection/connection.js:453:17)
  at Socket.emit (events.js:182:13)
  at addChunk (_stream_readable.js:283:12)
  at readableAddChunk (_stream_readable.js:264:11)
  at Socket.Readable.push (_stream_readable.js:219:10)
  at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
  errorLabels: [ 'TransientTransactionError' ],
  operationTime:
  Timestamp { _bsontype: 'Timestamp', low_: 2, high_: 1544250067 },
  ok: 0,
  errmsg: 'Transaction 1 has been aborted.',
  code: 251,
  codeName: 'NoSuchTransaction',
  '$clusterTime':
  { clusterTime:
    Timestamp { _bsontype: 'Timestamp', low_: 2, high_: 1544250067 },
    signature: { hash: [Binary], keyId: 0 } },
    name: 'MongoError',
    [Symbol(mongoErrorContextSymbol)]: {} }

Please mention your node.js, mongoose and MongoDB version.
node.js: v10.14.1
mongoose: 5.3.15
mongodb: 4.0.4

@adiliqbl adiliqbl changed the title TransientTransactionError, need help with transactions Transactions with Promise.all throwing TransientTransactionError Dec 8, 2018
@vkarpov15
Copy link
Collaborator

This is because you're doing 4 operations in parallel:

  • Role.collection.drop();
  • Permissions.collection.drop();
  • Permissions.createCollection()
  • role.validate()

So you've got a bunch of race conditions. Just use async/await and make your life easier.

await Role.collection.drop();
await Permissions.collection.drop();

 let permissions = [list];
 let session = null;
 
 console.log('Creating Roles');
await Permissions.createCollection() // Role is created automatically because of index
await roleQueries();

await role.validate();
const session = await Role.startSession();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants