JBoss.orgCommunity Documentation

Chapter 15. TorqueBox Distributed Transactions

15.1. Overview
15.2. The TorqueBox.transaction method
15.3. Messaging
15.4. Configuration
15.4.1. PostgreSQL
15.4.2. MySQL
15.5. Examples

TorqueBox takes advantage of its host's robust transactional facilities. JBoss provides state-of-the-art distributed XA transaction support, and TorqueBox exposes this to Ruby developers in a concise, often transparent API.

It's important to understand the difference between a conventional database transaction and a distributed transaction: multiple resources may participate in a distributed transaction. The most common example of a transactional resource is a relational database, but other examples include message brokers and some NoSQL data grids. Distributed transactions allow your application to say, tie the success of a database update to the delivery of a message, i.e. the message is only sent if the database update succeeds, and vice versa. If either fails, both rollback.

You may explicitly demarcate a transaction using TorqueBox.transaction. If the block of commands you pass to it runs to completion without raising an exception, the transaction is committed. Otherwise, it is rolled back. It's just that simple. It accepts the following arguments:

TorqueBox message destinations, background tasks and caches are all transactionally aware. They will enlist themselves in the transaction defined by TorqueBox.transaction automatically, by default.

In addition, Rails ActiveRecord models are enhanced when run in TorqueBox so that connections from multiple, class-specific databases can indeed participate in a single distributed transaction. Further, the behavior of nested transaction rollbacks won't surprise you: if the child rolls back, the parent will, too, excepting when the :requires_new=>true option is passed to the child. Callbacks for after_commit and after_rollback work as one would expect.

By default, all MessageProcessors are transactional, so each on_message(msg) invocation demarcates a transaction. If no exceptions are raised, the transaction commits. Otherwise, it rolls back. This is the default behavior and requires no additional configuration on your part.

Any messages published to any JMS destinations automatically become part of the current transaction, by default. So they won't be delivered until that transaction commits.

All Backgroundable tasks are transactional, so if invoked within a transaction, it will only start when the transaction commits.

Any manipulations of your Rails ActiveRecord models (persisted to your XA-compliant database) within on_message(msg) will become part of its transaction.

Occasionally, you may not want a published message to assume the active transaction. In that case, pass :tx => false, and the message will be delivered whether the active transaction commits or not. This option works for backgrounded tasks as well.

No extra configuration of your app is required other that what you'd normally do for a database-aware Ruby application, i.e. standard configuration of the activerecord-jdbc-adapter. See Chapter 14, Database Connectivity in TorqueBox for more details.

Distributed transactions are restricted to those databases supported by both the activerecord-jdbc-adapter and JBoss XA datasources. Currently, that includes PostgreSQL, MySQL, H2, Derby, Oracle, Microsoft SQL Server, and IBM DB2. Sqlite3 doesn't support XA. Default installations of some of these databases may require additional configuration to support XA.

Distributed transactions support comes enabled by default, so no extra configuration is required to enable it. If you don't need this feature, it is possible to disable it by setting xa to false in your database.yml. If your application uses more than one database, you'll need to enable distributed transactions explicitly for the additional databases by setting xa to true.