I’ve just finished watching an interesting set of slides about implementing transactions over HTTP using REST and the Try-Confirm/Cancel pattern.
The video and slides are available on the InfoQ site here http://www.infoq.com/presentations/Transactions-HTTP-REST and an easier to read version of the slides alone are visible here http://pautasso.info/talks/2012/soa-cloud-rest-tcc/rest-tcc.html#/title (note: you use the spacebar to progress through the slides)
Transactions for the REST of us
They start out by going over the typical issues – that HTTP is stateless and so doesn’t really support transactions where you may want to back out changes in multiple locations safely and consistently.
Their proposal has to be interoperable (no changes/extensions to HTTP), maintain loose coupling (so that REST services remain unaware that they are participating in a transaction) and simple enough that it is worth adopting.
The proposed Try-Confirm/Cancel pattern relies upon an initial state, a reserved state and a final state.
Try puts something into a reserved state.
Cancel (or Timeout) moves from the reserved state back to the Initial state.
Confirming a reserved state moves to the final state.
From a programmatic point of view
- Try – inserts into a reservation db
- Confirm – updates reservation, set status = confirmed
- Cancel – invalidate reservation
- Timeout – invalidate reservation
A number of service calls can then be wrapped into a single transaction by using a Transaction Coordinator service to handle the confirmations. So for example an event booking might reserve a seat from one service, pay via another service and then call the transaction coordinator which then attempts to confirm the payment and the reservation.
If there is a failure before confirmation, both services timeout and return to their original state. if there is a failure after confirmation, both services have been confirmed and are in their final state.
If there is a failure between reservation and confirmation, or between confirmation steps, then the transaction co-ordinator can either allow unconfirmed states to timeout or (perhaps better behaved) cancel those outstanding reservations and cancel any confirmations it has made before the failure occurred.
One particular advantage of this approach over a “workflow plus compensation” approach is that here the ‘undo’ functionality is pushed onto participant services rather than being a responsibility of an overall workflow. Thus services can timeout or cancel reserved states and error handling can be decoupled from the explicit workflow. This increased autonomy of participating services helps us keep our services decoupled and avoid the strong coupling that seems to ‘leak’ into our systems so easily.
This obviously isn’t a panacea solution to all ills – there will be some circumstances where it fits better than others. It fits particularly well into reservation-style business models (booking, purchasing from limited stock).