Concepts: Distributed Transactions

Joe Hegarty edited this page Apr 26, 2016 · 1 revision

Overview

Distributed Transactions in Orbit allow developers coordinate actions between various Orbit actors with the ability to rollback those actions in the event of a failure.

For instance, if a developer wishes to deduct currency from a user and then grant an item and these actions happens in different actors, distributed transactions would allow the developer to rollback to currency deduction if the item grant failed.

Using Distributed Transactions

Support

Distributed Transactions are currently only supported by actors which implement Transactional.

Out of the box, Orbit only supports Distributed Transactions when using the Event Sourcing persistence model without any further work required from the application developer. Developers are free to implement support for transactions in actors manually by implementing Transactional manually.

Basic Transaction

It is very simple to add a very basic transaction, interactions with the event source state are simply wrapped in a transaction.

public class BankActor extends EventSourcedActor<BankActor.State> implements Bank
{
    public static class State extends TransactionalState
    {
        int balance;

        @TransactionalEvent
        void incrementBalance(int amount)
        {
             balance += amount;
        }
    }

    public Task<int> creditBalance(int amount)
    {
        return transaction(() ->
        {
            state().incrementBalance(amount);
            await(writeState());
            return Task.fromValue(state().balance);
        }
    }
}

Complex Transaction

Complex transactions rely on each individual transaction to be wrapped in in a higher level transaction.

Transactions must wait for nested transactions to complete, this can be achieved using await. A more efficient implementation would send both messages in parallel and then await the response of both.

public class BankActor extends EventSourcedActor<BankActor.State> implements Bank
{
    public static class State extends TransactionalState
    {
        int balance;

        @TransactionalEvent
        void incrementBalance(int amount)
        {
             balance += amount;
        }

        @TransactionalEvent
        void decrementBalance(int amount)
        {
             balance -= amount;
        }
    }

    public Task<int> creditBalance(int amount)
    {
        return transaction(() ->
        {
            state().incrementBalance(amount);
            await(writeState());
            return Task.fromValue(state().balance);
        }
    }

    public Task<int> debitBalance(int amount)
    {
        return transaction(() ->
        {
            state().decrementBalance(amount);
            await(writeState());
            return Task.fromValue(state().balance);
        }
    }
}

public class TradingActor extends AbstractActor implements Trading
{
    public Task tradeMoney(Bank in, Bank out, int amount)
    {
        return transaction(() -> 
        {
          await(out.debitBalance(amount));
          await(in.creditBalance(amount));
          return Task.done();
        }
     }
}