10 ตุลาคม 2565

MongoDB retry transaction write conflict

 In MongoDB, if you have multiple sessions try to update same document in the same time, you will get TransientTransactionError, that means you found transaction write conflict error.


Solutions

1. Show the error on your website and let the user try again

2. Add your code to retry update your transaction automatically, see example here 

// Runs the txnFunc and retries if TransientTransactionError encountered

function runTransactionWithRetry(txnFunc, session) {
while (true) {
try {
txnFunc(session); // performs transaction
break;
} catch (error) {
// If transient error, retry the whole transaction
if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError") ) {
print("TransientTransactionError, retrying transaction ...");
continue;
} else {
throw error;
}
}
}
}

// Retries commit if UnknownTransactionCommitResult encountered

function commitWithRetry(session) {
while (true) {
try {
session.commitTransaction(); // Uses write concern set at transaction start.
print("Transaction committed.");
break;
} catch (error) {
// Can retry commit
if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
print("UnknownTransactionCommitResult, retrying commit operation ...");
continue;
} else {
print("Error during commit ...");
throw error;
}
}
}
}

// Updates two collections in a transactions

function updateEmployeeInfo(session) {
employeesCollection = session.getDatabase("hr").employees;
eventsCollection = session.getDatabase("reporting").events;

session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );

try{
employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
} catch (error) {
print("Caught exception during transaction, aborting.");
session.abortTransaction();
throw error;
}

commitWithRetry(session);
}

// Start a session.
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );

try{
runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
// Do something with error
} finally {
session.endSession();
}

MongoDB SELECT ... FOR UPDATE inside Transactions

 In MongoDB, if you want to lock document in the transaction, you need to update it.

The sample code below is to emulate SELECT FOR UPDATE in MongoDB, we need additional field "myLock" and we will utilize ObjectID function to make sure that it is unique.

var doc = db.foo.findOneAndUpdate(

    { _id: 1 }, 

    { $set: { myLock: { appName: "myApp", pseudoRandom: ObjectId() } } }

)


reference: How To SELECT ... FOR UPDATE inside MongoDB Transactions | MongoDB

08 ตุลาคม 2565

Debug Rust program on vscode (Visual Studio Code)

 Debug Rust program on vscode (Visual Studio Code)

  • Create new rust project by running cargo new hello
  • Open hello folder using vscode
  • Install vscode CodeLLDB extension
  • Make sure your .vscode/launch.json file will be like this (you can copy this JSON file)

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'hello'",
"cargo": {
"args": [
"build",
"--bin=hello",
"--package=hello"
],
"filter": {
"name": "hello",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'hello'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=hello",
"--package=hello"
],
"filter": {
"name": "hello",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

  • Set breakpoint and click debug Debug executable 'hello'


บทความยอดนิยม (ล่าสุด)

บทความยอดนิยม (1 ปีย้อนหลัง)