Distributed Transactions With Ballerina

Lasini Liyanage
3 min readJun 29, 2022
Source: https://danimosite.files.wordpress.com/

Among the many exciting features of Ballerina (some you may have already discovered!), is that it provides language support for distributed transactions. Since transactions play an integral role in business systems, unarguably Ballerina makes your life easy by providing you the capability of implementing scalable applications handling distributed transactions.
Let’s dive in… 😃

What is a distributed transaction?

A transaction that spans multiple external systems or services that are called sequentially or parallelly to complete the entire transaction can be termed a distributed transaction. These transactions also enable performing different operations on data across different databases.

How does Ballerina handle distributed transactions?

Transaction branches

With distributed transactions, a global transaction consists of multiple transaction branches, where a branch corresponds to work done by one strand of a Ballerina program that is part of the global transaction. Every transaction branch is uniquely identified by an XID, which consists of an identifier of the global transaction and an identifier of a branch with the global transaction. A strand’s stack of transactions is actually a stack of transaction branches.

Transaction Manager

A running instance of a Ballerina program includes a transaction manager. This may run in the same process as the Ballerina program or in a separate process. The transaction manager maintains a mapping from each strand to a stack of transaction branches. The transaction manager supports several abstract operations such as Begin(), Commit(), Rollback(), Info() etc.

Two-Phase Commit (2PC)

Maintaining a transaction’s atomicity and managing the transaction isolation level for concurrent requests are two crucial problems associated with distributed transactions. Ballerina addresses them using Two-Phase Commit (2PC) which splits the commit into 2 steps.

  • Prepare Phase: The transaction manager checks whether each participating node is ready to commit the transaction.
  • Commit Phase: If all nodes are ready to complete the transaction, the transaction manager asks the nodes to commit the transaction. If at least a single node is not prepared to complete the transaction, the transaction manager asks the nodes to rollback.

Language features

The following are some of the language features that will be useful for you when implementing distributed transactions using Ballerina.

  • Transaction statement: A transaction is performed using a transaction statement.
transaction {
// .... statements
}

The statement block must contain at least one commit action. The statement block of a transaction statement is a transactional scope, except for any statements that could potentially be executed after the execution of a commit action or rollback statement.

  • Commit action: Performs the transaction manager Commit() operation. The type of the result is transaction:Error?.
commit
  • Rollback statement: performs the transaction manager Rollback(e) operation, where e is the result of executing the expression, if present, and nil otherwise.
rollback [expression];

Both the commit and rollback are only allowed within the statement block of a transaction statement and they do not alter the flow of control.

Now, let’s take a look at a simple application of distributed transactions in an order management system.

After starting the initiator service and the participant service, execute the curl -v localhost:9091/init cURL command to invoke the services.

You’ll be able to see the following logs once you have invoked the services.

time = 2022-05-29T22:37:52.887+05:30 level = INFO module = lasini/distributed_trx message = "Transaction initiation..."
time = 2022-05-29T22:37:52.904+05:30 level = INFO module = lasini/distributed_trx message = "Transaction started: {\"xid\":[56,53,99,99,98,55,56,54,45,55,49,100,53,45,52,55,99,52,45,97,100,99,99,45,100,54,100,57,51,102,56,99,101,102,98,101],\"retryNumber\":0,\"prevAttempt\":null,\"startTime\":2022-06-29 22:37:52,900}"
time = 2022-05-29T22:37:53.250+05:30 level = INFO module = lasini/distributed_trx message = "Create order request recieved"
time = 2022-05-29T22:37:53.275+05:30 level = INFO module = lasini/distributed_trx message = "Sent response back to initiator"
time = 2022-05-29T22:37:53.277+05:30 level = INFO module = lasini/distributed_trx message = "Response received from Order Service"
time = 2022-05-29T22:37:53.285+05:30 level = INFO module = lasini/distributed_trx message = "Transaction committed"
time = 2022-06-29T22:37:53.287+05:30 level = INFO module = lasini/distributed_trx message = "Sent response back to client"

Hope you got an idea about writing distributed transactions in Ballerina! Let’s try out some more features in Ballerina in the upcoming articles! 😃

--

--