Transactions are too slow, very slow

I have implemented transaction in MongoDB as described in this article:

Utils.js

import { MongoInternals } from 'meteor/mongo';

// utility async function to wrap async raw mongo operations with a transaction
export const runTransactionAsync = async function (asyncRawMongoOperations, errorCode) {

// setup a transaction
const { client } = MongoInternals.defaultRemoteCollectionDriver().mongo;
const session = await client.startSession();
await session.startTransaction();
try {
    // running the async operations
    let result = await asyncRawMongoOperations(session);
    await session.commitTransaction();
    // transaction committed - return value to the client
    return result;
} catch (err) {
    await session.abortTransaction();
    console.error(err.message);
    // transaction aborted - report error to the client
    throw new Meteor.Error(errorCode, err.message);
} finally {
    session.endSession();
}
};

Example of using the transactions:

Meteor.methods({
   'changeLanguage': async function(poemId, newLanguageId) {

        // define the operations we want to run in transaction
        const asyncRawMongoOperations = async session => {

            const poem = Poems.findOne({ _id: poemId });
            const prevLanguage = poem.languageId;

            const profile = Profiles.findOne({ userId: this.userId });

            await Profiles.rawCollection().update(
                { userId: this.userId }, 
                    { 
                        $inc: { 
                            ['countLanguages.' + prevLanguage]: -1,
                            ['countLanguages.' + newLanguageId]: 1 
                        },
                        $addToSet: { languages: newLanguageId }
                    }, 
                    { session: session }
                );

            await Poems.rawCollection().update({
                    '_id': poemId,
                    'userId': this.userId
                },
                {
                    $set: {
                        languageId: newLanguageId
                    }
                }, 
                { session: session }
            );

            return true; // will be the result in the client
        };

        let result = await runTransactionAsync(asyncRawMongoOperations, 'Error-01');

        return result;
    }
});

At localhost it works well, fast, with no issue.
But at MongoDB hosting (MongoDB.Atlas. MongoDB v 4.0.12., cluster tier M10) it is very very slow. It can take up to 7 seconds.

The database is almost empty, max 50 records in each collection.

If I remove .rawCollection() it start to work fast, but transactions stops to work.

Where can be the bottleneck in this case?

Thanks in advance!

2 Likes

Maybe try using the Performance API and some timestamps to see where the execution slows down in your code, and then continue (if necessary) by profiling MongoDB: https://docs.mongodb.com/manual/tutorial/manage-the-database-profiler/

1 Like

Thanks Arggh,
I will have to do this, I think.
I see that transactions are quite new topic for Meteor+MongoDB. There is no so much information about this. Meteor team could write more about this, create some examples.

I’m sure whatever you learn in the process about MongoDB transactions with Meteor is very welcome to the Meteor guide as a PR!

3 Likes

I understod this problem.

My app is build on React. The component which shows changes is waiting date from subscription. When I run the transaction it works fast and the result from
‘changeLanguage’: async function(poemId, newLanguageId) {
comes at once, no delay.

Delay happens in updating of the object through subscription. So it takes some seconds that subscription gets new changes.

Another observation: If I remove all .rawCollection() in ‘changeLanguage’ there is no delay, but transaction does not work. So there is something to do with .rawCollection.

So now my question: Is it normal that it takes so much time when subscription see changes? How to improve it?

Usually it takes only dozen of milliseconds to see changes.

Yes, if changes was initialized without using .rawCollection. in my case. Can it be the reason?

I don’t have experiences of working with mongodb transaction. I can’t tell.

1 Like