Specification of how to model transactions as RESTful resources
This wiki article will discuss two approaches to providing transactional guarantees for updating resources modeled using the REST paradigm.
An implementation of the protocol is available in the download section below (or via svn from the private JBossTS workspace repository). It uses the RESTEasy implementation of the JAX RS specification. The JBossTS transaction manager is employed as the protocol coordinator.
We do not discuss whether or not transactions and REST are a good architectural fit suffice to say that there are proponents for both sides of the argument. Certainly it is worth pointing out that if a system cannot be made reliable then it can be of only limited utility. That said it is a worthwhile exercise to show how a REST based system can be made reliable.
The two proposals are:
Approach 1 is discussed in depth whilst the second will be covered in a subsequent wiki.
Disclaimer: Although the following protocol is viable it was in fact written over 8 years ago by another community member, namely Mark Little. Things have moved on since then and we do plan to re-evaluate the specification.
The protocol makes use of three resource types:
A client is the entity that wishes to manipulate resources within the context of a transaction. It may or may not be modeled as a resource.
All actors are modeled as URLs, the idea being that doing PUT, DELETE, GET and POST to the various URLs will control how a transaction makes progress and how changes to resources are processed reliably (ie obey ACID properties).
POST is used to create resources, PUT will modify a resource and GET retrieves a resource:
URL | GET | PUT | POST |
---|---|---|---|
TC | Return all transactions (1) | ||
TC/recovery | Return all recovering transactions (2) | ||
TC/active | Return all active transactions (3) | ||
TC/begin?clientId={id} | Start a transaction (with default timeout) returns url TC/{txid} which is deleted after the timeout or after completion (any HTTP method relating to {txid} thereafter returns 404) | ||
TC/begin?clientId={id}&timeout={timeout} | Start a transaction (with specified timeout) returns url TC/{txid} which is deleted after the timeout or after completion (any HTTP method relating to {txid} thereafter returns 404) | ||
TC/{txid}/commit | Trigger commit (4) | ||
TC/{txid} | Return the transaction status (5) | ||
TC/{txid}?P-URL={url} | Enlist url in the transaction returning a unique resource for that participant of the form RC/{RecCoordId} | 401 | |
RC/{RecCoordId} | Return the participant URL | Replace the participant URL (7) | 401 |
P-URL | Return the status of this participant. A status is any of the statuses returned by prepare and commit | ||
P-URL/prepare | 400 | 401 | The participant prepares any work done in the context of the transaction (see note 6). Returns a status URL indicating the outcome:
|
P-URL/commit | 400 | 401 | The participant commits any work done in the context of the transaction (see note 6). Returns a status URL indicating the outcome:
|
P-URL/rollback | 400 | 401 | The participant rolls back any work done in the context of the transaction (see note 6). Returns a status URL indicating the outcome:
|
P-URL/forget | Returns the status if a heuristic exists and 404 otherwise | 401 | The participant forgets any heuristic decision |
The prototype is available via svn (for restricted users) or from the download section below.
Unpack the distribution (or check out from svn), make sure you have maven installed, and run the tests:
mvn clean install
The tests start up an embedded servlet container for testing the protocol. To run using a stand-alone container (the distribution uses jetty6, but any container would do) type:
mvn jetty6:run-exploded
To skip the tests pass -Dmaven.test.skip=true mvn (via MAVEN_OPTS).
There is also an ant build script which performs a simple test against the jetty container.
You can change logging levels via the log4j script in the file src/test/resources/log4j.xml
If you want to test recovery, edit the test org.jboss.jbossts.rts.testAppTest.test6 and change the crashVM variable to true and run the tests. The VM running the test will halt. Change crashVM variable back to false and start the server. You will see the recovery sub-system replaying the failed transaction. The way I've got things set up at the moment is for the example participant to refuse the the request since it does not persist its work. I might change this in the next update of the prototype.