I am having an issue with mongodb driver that I am not able to understand.
Some context. I am creating an NFT collection ranker endpoint. To that end I am attempting to store processed data in two separate collections rankings and sortedRankings. rankings contains collection level data and sortedRankings contains the sorted collection.
I found out about mongodb transactions and decided to give it a shot. Here is the associated code in question.
export async function rankingInsertOrUpdate(
storedAccuracy: WithId < NFTCollectionRanking > | null,
rankingDocument: NFTCollectionRanking,
sortedRankingDocument: NFTSortedRanking
) {
const session = client.startSession();
try {
if (storedAccuracy === null) {
runTransationWithRetry(insertRankings, session);
} else if (rankingDocument.accuracy > storedAccuracy.accuracy) {
runTransationWithRetry(updateRankings, session);
}
} catch (error: any) {
throw new Error(error);
} finally {
session.endSession();
}
async function insertRankings() {
session.startTransaction({
readConcern: {
level: 'snapshot'
},
writeConcern: {
w: 'majority'
},
});
try {
await rankings.insertOne(rankingDocument);
await sortedRankings.insertOne(sortedRankingDocument);
} catch (error) {
console.log('Caught exception during insert transaction, aborting.');
session.abortTransaction();
throw error;
}
commitWithRetry(session);
}
async function updateRankings() {
session.startTransaction({
readConcern: {
level: 'snapshot'
},
writeConcern: {
w: 'majority'
},
});
try {
await rankings.updateOne(rankingDocument);
await sortedRankings.updateOne(sortedRankingDocument);
} catch (error) {
console.log('Caught exception during update transaction, aborting.');
session.abortTransaction();
throw error;
}
commitWithRetry(session);
}
}
function runTransationWithRetry(txnFunc: any, session: any) {
while (true) {
try {
txnFunc(session); // performs transaction
break;
} catch (error: any) {
// If transient errorm retry the whole function
if (
error.hasOwnProperty('errorLabels') &&
error.errorLabels.includes('TransientTransactionError')
) {
console.log('TransientTransactionError, retrying transaction ...');
continue;
} else {
throw error;
}
}
}
}
function commitWithRetry(session: ClientSession) {
while (true) {
try {
session.commitTransaction(); // Uses write concern set at transaction start
console.log('Transaction committed');
break;
} catch (error: any) {
// Can retry commit
if (
error.hasOwnProperty('errorLabels') &&
error.errorLabels.includes('UnknownTransactionCommitResult')
) {
console.log(
'UnknownTransactionCommitResult, retrying commit operation ...'
);
continue;
} else {
console.log('Error during commit ...');
throw error;
}
}
}
}
Whats happening specifically is that node is crashing at the very last second. Here is a pic of the console logs.
I run the POST, let it process everything, then it crashes. The processed data appears in my DB. So it is successful in sending it to the DB, but I'm not able to find out why abortTransaction is being called. If an error was thrown during the insertRankings or updateRankings function, then it would've console logged Caught exception during insert transaction, aborting, but this is not appearing in my terminal. The only statement printed is Transaction committed. The session is also ended with session.endSession() after runTransactionWithRetry is finished. Not sure how it's successful but crashes at the end.
I used the retry flow from the mongo docs found here https://www.mongodb.com/docs/manual/reference/method/Session.startTransaction/ . I tried following it a T. I have checked other posts like mongodb do I need a abortTransaction after commitTransaction that fails? and MongoError: Cannot call abortTransaction twice; MongoError: Cannot call abortTransaction after calling commitTransaction but they do not help answer my question.
I'm kinda stumped and any help would be amazing.
