Wednesday, December 20, 2017

Narayana LRA: implementation of saga transactions

The Narayana transaction manager implements saga transactional pattern naming it as LRA which is abbreviation to Long Running Action.
This saga implementation is basis for the specification fitting to schema of Eclipse MicroProfile. See at https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA.

The communication is done over HTTP in way of REST principles.
The Java EE technologies which the LRA builds upon are CDI and JAX-RS.

Saga - what we are talking about

Before we start talking about LRA let's introduce the term saga.
Saga consists from independent set of operations which all together forms one atomic action. The operation can be whatever action you think.

Here we took take the well known example of booking a flight and subsequent services. The operations are booking flight, taxi and hotel and these three forms the atomic action which we want all parts would be processed together.




NOTE: From ACID point of view the Saga transaction relaxes the I (isolation) and because of that gets availability and is representation of BASE principle, see http://queue.acm.org/detail.cfm?id=1394128.

Principle of saga requires existence of a compensations actions invoked in case of failure.


The compensation actions undo work done by the "business" operations. The sequence in case of the flight example is first to book flight. If that success this change is overly visible to all the other parties trying to book the flight too (here it's the relaxation of ACID isolation).
Next is the taxi booking, followed by hotel booking. When there is no hotel available in the area for the particular date the whole saga fails and compensation action for the prior actions are invoked. The responsibility of the compensation action is undoing what was done - in this case canceling flight and taxi booking. How this is exactly done depends on the business logic. It could be updating of some database record, call to some API or sending email to the taxi operator.

In comparison to ACID transaction, where developer makes a SQL insertion to database or sends a message to a broker and the potential undoing such action (rollback) is handled by the transaction manager in the background, here in Saga world the responsibility of undoings completely moved to the developer who has to implement the compensations callback.

Responsibility of the transaction manager is to gather information about what operations are part of particular saga (receives participant enlistment) and ensuring the compensation callback is invoked, even in case of failure (either the participant or the manager itself).

The Narayana LRA implementation also adds way to define a complete callback which is invoked when saga ends successfully. This could be used for confirmation actions e.g. customer could be informed with email that order was processed while passing him details needed for the payment. Or database can be enriched with column informing if order was successfully processed and SQL statements could be created with that taken into account.

In summary using saga transactions is a design pattern which needs to be built to the foundation of the application architecture.

LRA - Long Running Actions

The Narayana LRA is implementation of saga for HTTP transport based on the REST principles.

Narayana LRA is represented by coordinator (transaction manager) exposing HTTP endpoint for an incoming remote communication. The coordinator is the core which ensures the LRA saga is processed in atomically. Services enlist to the coordinator, by calling defined REST endpoints. The coordinator calls then back services to confirm saga success or command to undone with compensate.

The coordinator can be placed as separate service or it can be attached to the application too.

For Narayana implementation applies that in case of coordinator packed with the application, the application itself talks to coordinator with in-memory calls.

Let's explain how the LRA communication works on the example. This is diagram showing our usecase.



We can see the LRA coordinator and 4 services talking to each other in the row synchronously (of course your application can be designed in a different way) and communication will looks in following way
  1. A client makes a call to the first service (Microservice #1)
  2. The Microservice #1 is responsible for starting LRA (creating the saga). It calls LRA coordinator to endpoint starting LRA. The coordinator announces lra identifier in response.
  3. The Microservice #1 enlists itself with the created LRA by calling coordinator along with the particular LRA identifier and handing over addresses of REST endpoints for compensation (optionally completion) callbacks. Those are endpoint the coordinator can call back to Microservice #1.
  4. The Microservice #1 takes the LRA identifier and adds it as an HTTP header (long-running-action) to the REST call to the next service - Microservice #2. If the Microservice #2 distinguishes the LRA header it can enlist itself (by announcing REST endpoints for compensation/completion callbacks) to coordinator.
  5. On way back the first service is responsible for finishing saga by calling close (when finishing with success) on the LRA coordinator with the saga identifier.
  6. Some of the other services could fail saga by calling cancel on the LRA coordinator, in which case the close won't succeeds and reports back an error.

Code examples

If you wan to see this example working check out the Red Hat MSA example
enriched with the LRA capabilities.
Detailed installation steps could be found at the page: https://developer.jboss.org/wiki/MSAQuickstartsWithLRAREST-ATOnMinishift

In the next article we will get into CDI annotations used by LRA and their functionality. Meanwhile you can check out how the WildFly Swarm microservice using LRA described in the example looks like
https://github.com/ochaloup/hola/blob/lra/src/main/java/com/redhat/developers/msa/hola/HolaResource.java#L81

or check other implementations run with Spring, Vert.x and Node.js

4 comments:

rafaelcba said...

Hi!
Could you please clarify how the LRA coordinator manages the SAGAs Log (state)? It uses the same object store used by JTA/JTS in narayana?

Another question is about how can I register/enlist an external service not owned by me in the LRA Coordinator service? (eg. a public remote service API from Google or any other api/service provider)

Michael Musgrove said...

The Narayana implementation of LRA builds on the same foundation (ArjunaCore) as our other transaction related projects so it does indeed use the same transaction log storage mechanism. Whenever the state of an LRA changes, the new state is made persistent (via the Narayana transaction object store). The store location is configurable via properties (see the Narayana Project Documentation). We have various storage options such as the file system, artemis journal, or a database.

There are two ways to register a service for LRA completion/cancellation notifications:

- create a JAX-RS resource that contains specific Java annotations defined in the MicroProfile LRA specification (minimally @LRA and @Compensate).
- issue an HTTP request to our proprietary LRA coordinator and include endpoints that should be called when the LRA later cancels or closes (you will also need to include the id of the LRA).

So if the external service is not under your control you would need to create a proxy that does know how to enlist with an LRA. If your proxy is asked to compensate then you would need to call the relevant logic in the external service (that executes the appropriate compensation behaviour).

Михаил Мерков said...

Hi,

I saw, that you have intensive development of the LRA project at GitHub following the current state of the Microprofile LRA.

My question here is when and where you will post documentation about your implementation?

Best Regards,
Mihail

Ondra Chaloupka said...

Hi Михаил Мерков,

we are working on finishing the LRA 1.0 spec (https://github.com/eclipse/microprofile-lra/milestone/1) and to align the Narayana implementation (https://github.com/jbosstm/narayana/tree/master/rts/lra) with it.

The Narayana LRA implementation tracks the progress as issues under RedHat Jira issue of project JBTM - see here https://issues.redhat.com/browse/JBTM-3294?jql=project%20%3D%20JBTM%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20LRA%20ORDER%20BY%20priority%20DESC. There are few blockers and critical issues which needed to be addressed.

There are not many issues to be finished so we hope this all will be covered soon. Regarding documentation - we've been discussing this on the google forum (https://groups.google.com/g/narayana-users/c/Lmsxt-nGDUk/m/faNbVo8oAgAJ). The current status is that the Narayana documentation will be updated following the LRA 1.0 release.

The LRA specification and Narayana are both open-source projects and the contribution is more than welcomed. That will speed things along.

Kind regards, Ondra