How to run two-phase commit transaction
ScalarDB GraphQL supports two-phase commit style transactions
called Two-phase Commit Transactions.
With Two-phase Commit Transactions, you can execute a transaction that spans multiple
processes/applications (e.g., Microservices).
We name the application that starts a transaction "coordinator" while the applications that
join the transaction are named "participants".
Every two-phase commit operation requires annotating the mutation or query operation with
a @twoPhaseCommit
directive. Below is a description of such operations.
Start a transaction
To start a transaction, add the @twoPhaseCommit
directive without setting parameters.
query some_query @twoPhaseCommit {
# some query
}
The transaction ID of the started transaction will be returned in the extensions object that is part of the result.
{
"data": {
...
},
"extensions": {
"transaction": {
"id": "the_transaction_id"
}
}
}
Join a transaction (for participants)
In a participant application, to join the transaction started by a coordinator application, set the
transaction ID with the id
parameter and set the join
parameter to true.
query some_query_from_participant @twoPhaseCommit(id:"the_transaction_id", join:true) {
# some query
}
Resume a transaction
To continue executing operations in the started or joined transaction, set the transaction ID value in
the id
parameter of @twoPhaseCommit
directive.
mutation some_mutation @twoPhaseCommit(id:"the_transaction_id") {
# some mutation
}
Prepare, validate and commit a transaction
After finishing the query and mutation operations, you need to commit the transaction. Like a well-known two-phase commit protocol, there are two phases: prepare and commit. You first need to prepare the transaction in all the coordinator/participant applications, and then you need to commit the transaction in all the coordinator/participant applications.
If the Consensus Commit transaction manager is configured with the EXTRA_READ
serializable strategy
in SERIALIZABLE
isolation level, an extra "validate" phase is required between prepare and
commit phases.
Similarly to prepare and commit, validate need to be executed in all the coordinator/participants
applications.
Prepare, validate and commit can be executed in parallel with all the coordinator/participants applications.
Prepare a transaction
Two options are possible to prepare a two-phase commit transaction.
Via the directive parameter
By using the prepare
parameter of the directive, the transaction will be prepared after the
execution of the operation fields and only if they do not raise an error.
mutation some_mutation_then_prepare_tx @twoPhaseCommit(id:"the_transaction_id", prepare:true) {
mutation1 : ...
mutation2 : ...
# the transaction will be prepared after the execution of the mutation1 and mutation2 fields
}
Via the mutation field
Add a prepare
field in a mutation operation. This field will trigger the transaction
preparation.
mutation prepare_tx @twoPhaseCommit(id:"the_transaction_id") {
prepare
}
Validate a transaction
Add a validate
field in a mutation operation. This field will trigger the transaction
validation.
mutation validate_tx @twoPhaseCommit(id:"the_transaction_id") {
validate
}
Commit a transaction
Add a commit
field in a mutation operation. This field will trigger the transaction commit.
mutation commit_tx @twoPhaseCommit(id:"the_transaction_id") {
commit
}
Abort/Rollback a transaction
When you need to abort/rollback a transaction explicitly, you can use the abort
or rollback
mutation fields interchangeably (both have the same effect and usage). Note that you cannot mix it
with any other operations, so you must specify it alone.
mutation AbortTx @twoPhaseCommit(id: "the_transaction_id") {
abort
}
or
mutation RollbackTx @twoPhaseCommit(id: "the_transaction_id") {
rollback
}