Transactions

In workflow, similar to SQL, a transaction symbolizes a unit of work performed against one or more entities where all changes either succeed or fail at the same time.

Transactions are defined at method level using the keyword atomic as in the following example:

method atomic work() { var p = CREATE product; p.name = "Some product"; PUT p; //both PUT statements either succeed or fail var s = CREATE sale; s.id_product = p.key; s.value = 100; PUT s; //both PUT statements either succeed or fail }

Inheriting transactions

When creating complex programs the code may be split among many methods or functions so how transactions work in this context? Here comes into play transaction inheritance. Here is the previous example split into two methods:

method atomic work() { var s = CREATE sale; s.id_product = this->createProduct("Some product"); s.value = 100; PUT s; } function createProduct(name as string) as int { // ^-- the atomic keyword is not specified var p = CREATE product; p.name = "Some product"; PUT p; return p.key; }

The createProduct function doesn't not specify the keyword atomic meaning that it inherits the transaction from the caller. So if the caller, in this case the work method, has a transaction defined than the callee uses the same transaction.

But what if we want the callee to run in it's separate transaction?

If you want a method to run in its separate transaction the keyword isolated must be used. Now let's see the same example, only this time, the createProduct function runs in a separate transaction:

method atomic work() { var s = CREATE sale; s.id_product = this->createProduct("Some product"); s.value = 100; PUT s; } function isolated atomic createProduct(name as string) as int { // ^-- the isolated keyword is defined var p = CREATE product; p.name = "Some product"; PUT p; return p.key; }

The createProduct function specifies the  keyword isolated meaning that it is isolated from the transaction of the caller. So if the caller, in this case the work method, has a transaction defined than the callee will create its own new transaction.

Using the keyword isolated on its own will make the method or function isolated from the caller but not transactional. If the method should also be transactional the keyword atomic must be specified.

Inheritance happens only if the callee (1) has no transaction defined or (2) the caller's and the calle's transactions are atomic. In the following table describes all the inheritance scenarios available:

Caller transaction

Callee transaction

Inherits

Atomic

Caller transaction

Callee transaction

Inherits

Atomic



atomic

No

Yes



isolated

No

No



isolated atomic

No

Yes





Yes

Inherited

atomic

atomic

Yes

Yes

atomic

isolated

No

No

atomic

isolated atomic

No

Yes

atomic



Yes

Yes

isolated

atomic

No

Yes

isolated

isolated

No

No

isolated

isolated atomic

No

Yes

isolated



Yes

No

isolated atomic

atomic

Yes

Yes

isolated atomic

isolated

No

No

isolated atomic

isolated atomic

No

Yes

isolated atomic



Yes

Yes