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.