2

I'm using Mongoose and Node.js. I have to preform 3 update operations & 1 insert operation in a transaction. I use Promise.all() for this, as seen below. Sometimes, very randomly, it throws the following error:

(note that the numbers are different based on the request, i.e. the first request says transaction number 1 does not match... active transaction number is -1, second request says transaction number 2 does not match... active transaction number is 1 and so on...

MongoError: Given transaction number 2 does not match any in-progress transactions. The active transaction number is 1
    at MessageStream.messageHandler (C:\Users\WIN 10\desktop\ether\node_modules\mongodb\lib\cmap\connection.js:268:20)
    at MessageStream.emit (events.js:310:20)
    at processIncomingData (C:\Users\WIN 10\desktop\ether\node_modules\mongodb\lib\cmap\message_stream.js:144:12)
    at MessageStream._write (C:\Users\WIN 10\desktop\ether\node_modules\mongodb\lib\cmap\message_stream.js:42:5)
    at doWrite (_stream_writable.js:442:12)
    at writeOrBuffer (_stream_writable.js:426:5)
    at MessageStream.Writable.write (_stream_writable.js:317:11)
    at TLSSocket.ondata (_stream_readable.js:695:22)
    at TLSSocket.emit (events.js:310:20)
    at addChunk (_stream_readable.js:286:12)
    at readableAddChunk (_stream_readable.js:268:9)
    at TLSSocket.Readable.push (_stream_readable.js:209:10)
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:186:23)

This happens randomly, sometimes it doesn't even happen, but usually it happens for 1 or even 2 of the operations in the Promise.all() in the below code.

const session = await mongoose.startSession();
session.startTransaction();

        try {
                        // Perform 3 update operations & 1 insert operation
            const result = await Promise.all([
                User.findOneAndUpdate(
                    {
                        _id: recipientId,
                        $expr: { $lt: [{ $size: '$matches' }, '$matchSlots'] }
                    },
                    {
                        $push: { matches: { matchId: senderId } }
                    },
                    { session }
                ),
                User.findOneAndUpdate(
                    {
                        _id: senderId,
                        $expr: { $lt: [{ $size: '$matches' }, '$matchSlots'] }
                    },
                    {
                        $push: { matches: { matchId: recipientId } }
                    },
                    { session }
                ),
                Like.findOneAndUpdate(
                    // Make Like inactive, as it was accepted
                    { to: senderId, from: recipientId },
                    { isActive: false },
                    { session }
                ),
                Like.create(
                    [
                        {
                            to: recipientId,
                            from: senderId,
                            isActive: false
                        }
                    ],
                    { session }
                )
            ]);

            await session.commitTransaction();
            session.endSession();
            res.sendStatus(200);
        } catch (err) {
            await session.abortTransaction();
            session.endSession();
            console.log(err);
            res.send(err);
        }

The error is thrown whenever I use a Promise.all() with more then 1 operation in it, however it happens randomly. It never happens (at least I havent encountered it) when there is only one operation, but when there is more then 1 operation it seems to have about a 50% chance of happening for each of the operations.

The expected behavior is to not throw any error (unless it's a MongoDB duplicate value error, in which case session.abortTransaction() is called), and simply complete the 4 operations. I need to use transactions for this, as if one of the 4 promises returns null, I need to abort the transaction.

P.S. I can't use withTransaction(), as while It does fix the error completely, I need to access the edited documents later on and do some validation and maybe abort the transaction.

EDIT

I fixed the issue. I just used withTransaction() and did all the validation in there. I did not know that was a possibility before.

George
  • 521
  • 1
  • 7
  • 17

0 Answers0