Wednesday, September 30, 2015

JTS Docker Container

So last week our new Docker image became available on https://hub.docker.com. It is a standalone JTS service running the premiere open source transaction manager written by the Narayana team.
In addition to that, it comes with a helper image - JacORB name server, which provides an easy way of sharing the transaction managers IOR.
The transaction manager image can be found here:
And the JacORB name server image can be found here:

Usage

This image comes with a quickstart example available on Narayana Github page: https://github.com/jbosstm/quickstart/tree/master/jts-docker. But here I’ll provide a brief extract from the quickstart to explain how the JTS Docker image can be used.
We use Docker linking technology to make interaction between JTS and JacORB containers more smooth. Thus JTS container expects certain environments to be available. Not to worry though, they are automatically created by Docker.
Here is how to start the name server container:
docker run -p 3528:3528 -it --name jacorb-name-server jboss/jacorb-name-server
And this is how to start JTS container on Linux, linking it with the name server:
docker run -p 4711:4711 -it --link jacorb-name-server:jacorb-name-server --name jts-transaction-service jboss/jts-transaction-service
Or if you're running on Boot2Docker start JTS container as follows:
docker run -p 4711:4711 -it -e "PROXY_IP={Boot2Docker IP}" --link jacorb-name-server:jacorb-name-server --name jts-transaction-service jboss/jts-transaction-service
And that is it. Now you can connect to the name server from your application and retrieve the IOR of the transaction manager. Pretty easy.
Of course, since Docker container storage is removed once the container is removed, this is not the best way to use any transaction manager as you will want to make sure your transactions are completed even in case of the system failure. To avoid such scenarios and make the transaction log reliable you have two options: mount a host directory or use JDBC object store.
But you can read more about that in our quickstart readme:
Additionally, in the quickstart you’ll find an example of how to coordinate JacORB name server and JTS transaction service containers with Kubernetes.

Thursday, September 10, 2015

Updating multiple one-phase resources with Narayana

I was recently forwarded a link to an article regarding the use of Springs chained-transaction manager facility wherein the author had utilised this facility to coordinate updates to multiple one-phase resources. This gave me the opportunity to show-case a Narayana facility which has existed for many years that allows you to build something with similar a similar purpose and possibly richer properties.
What we will create is an application that uses multiple one-phase resources (for example, some hypothetical none-XA database and message queue). We will use Narayanas AbstractRecord extension mechanism to order the commit messages to the resource managers in any way that would be appropriate for the application. We will then take a look at some options for failure recovery options.

Notes:

  • Applications of this style (i.e. multiple 1PC) are only suited for certain classes of applications. Where possible it is almost always preferable to use 2PC resources to provide spec-compliant transactional outcomes.
  • The code I am going to use to demonstrate some of this is derived from a unit test in our repository but I will extract some of the code to below. I won't actually use resource managers in this example to try to illustrate the pattern as clearly as possible.
  • If the test ever moves around, you can probably track it via its SHA 8e9f712d5b89762c7b841cf370eb5bdb341fff4d.

Transactional business logic

The general layout of the application follows the same pattern of any other transactional application:
        // Get references to resource managers
        ResourceManager1 rm1 = ...;
        ResourceManager2 rm2 = ...;

        // Create a transaction
        AtomicAction A = new AtomicAction();
        A.begin();

        // Enlist resource manager in transaction
        A.add(new OrderedAbstractRecord(rm1));
        A.add(new OrderedAbstractRecord(rm2));

        // Do business logic
        // rm1.sendMessage()
        // rm2.doSQL()

        // Commit the transaction, the order will be defined in OrderedAbstractRecord rather than
        // the business logic or AtomicAction::add() order
        A.commit();

Guaranteeing the order of commit messages

The ordering of the list for transaction completion events is dictated by the RecordList class. At the most fundamental level, for AbstractRecords of the same type it is determined by the Uid returned in the AbstractRecords order method. As Uids are sequentially numbered at some level, this basically means that if you return a Uid lower to a peer, your record instance will be committed before that one.
So for example, the order of Uid you allocate to the following class will determine the order AbstractRecord::topLevelCommit() is called:

public class OrderedOnePhaseAbstractRecord extends AbstractRecord {
    public OrderedOnePhaseAbstractRecord(Uid uid)
    {
        super(uid);
        order = uid;
    }
    public Uid order()
    {
        return order;
    }
    //...
}

Failure tolerance properties

A final observation to make is that by using the Narayana AbstractRecord facility, it allows you to know that in the presence of a failure, during crash recovery you will receive callback where it may even be possible to re-do some of the work in the later resources.
For example, in the AbstractRecords save_state you could save some of the content of the JMS message which can then be used in a possible recovery scenario to resend a similar message.