Skip to content

jefrajames/lra-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MicroProfile LRA demo

This project demonstrates how to use MicroProfile Long Runing Actions on a concrete use case.

It has been showcased during talks at Devoxx France, Bordeaux JUG, DevFest Lille, BreizhCamp, Paris JUG.

A similar example based on Eventuate Tram Saga is available on GitHub.

It is made of 3 modules :

  1. lra-coordinator: acts as a lightweight Transaction Manager, based on Narayana

  2. Holiday: the edge service exposed to the outside. Starts the LRA and invokes specialized backend services such as trip, hotel and car. In this version, only trip is implemented. Feel free to download this example and to complete it with the 2 other services. This will be a good exercice!

  3. Trip: a backend service invoked by Holiday.

Technical architecture

lra demo architecture

Comments:

  1. Both services are implemented with Quarkus

  2. They expose a REST API and use CDI and JPA internally

  3. Narayana acts as LRA Coordinator, it is packaged and run as a Quarkus project

  4. Jaeger is used to trace the traffic between the services and Naryana. This allows to understand how LRA works behind the scene

  5. Both services have their own database schema. For the sake of simplicity a single PostgreSQL server instance is used.

Technical context

As of this date (June 2022), the following technical context has been used:

  1. Java 17

  2. Quarkus 2.13.3.Final

  3. GraalVM 22.2.r17-grl

  4. Maven 3.8.6

  5. docker compose

It has been developped on Linux. Some fixes may be required on MacOS or Windows. Docker images support arm64 (Mac M1) architecture.

Ports in use

Several TCP ports are used by this demo:

  1. Jeager: 3306

  2. Postgres: 5432

  3. LRA Coordinator: 50000

  4. Trip : 8082

  5. Holiday : 8080

How to build

Run mvn clean package in the main directory.

How to start the demo

Start Jeager and PostgreSQL

Jeager et PostgreSQL are run with docker compose.

To start them:

  1. cd lra-infra

  2. ./start-infra.sh: previous containers and volumes are pruned to start with a fresh situation.

Start the LRA Coordinator

LRA Coordinator is a standard Quarkus project:

  1. cd lra-coordinator

  2. ./start-coordinator.sh: the ObjectStore directory, where transactions are stored, is removed before running Naryana to start with a fresh situation.

Start Trip

  1. cd trip

  2. ./start-trip.sh

Start Holiday

  1. cd holiday

  2. ./start-holiday.sh

Understanding the demo

Before running the demo, it is important to understand the processing in place:

lra demo processing

Comments :

  1. Holiday acts as the edge service exposed to the outside. When receiving a HolidayBookResource, it starts the LRA and checks the customer id (accepted value: 42)

  2. It invokes Trip which checks the departure (accepted value: Paris) and the destination (accepted values: London, Dublin, Budapest, Barcelona), determines the transport (BOAT, TRAIN, PLANE) and the time schedule

  3. Invoking Hotel and Car is not yet implemented

  4. Holiday cheks the total price that shouldn’t exceed 500.00

The LRA is started when receiving a HolidayBookRequest.

It is canceled if:

  • Customer id is NOK

  • Departure and destination are NOK

  • Total price exceeds the maximum value

  • In case of timeout

It is accepted if all checks are OK with no timeout.

How to run the demo

All the demo can be run with Holiday Swagger UI: http://localhost:8080/q/swagger-ui/

LRA trafic can be checked with Jaegger UI: http://localhost:16686/search. Choose lra-coordinator, holiday or trip services to understand what happens behind the hood.

Trip Swagger UI can also be used to check the status of Trip entities: http://localhost:8082/q/swagger-ui/

Demo 1: accepted book request

From Holiday Swagger UI:

  1. Chose HolidayResource POST "Book a Holiday with LRA"

  2. Select "Let’s go to London" from the examples

  3. Try it and execute it.

The response status should be ACCEPTED.

You can check the LRA requests sent to the coordinator with Jeager GUI:

  1. a LRA has been started

  2. 2 participants have joined it

  3. it has been closed normally.

Check the consistency of the Trip entity:

  1. get the trip_id value of the response in Holiday Swagger UI

  2. go to Trip Swagger UI and select "find by id"

  3. the status should be ACCEPTED.

Demo 2: customer id NOK

From holiday Swagger UI: . change the customer id value to 4 . execute it.

The request has been rejected by Holiday with a business error "Unknown customer".

With Jaeger GUI you can check that:

  1. a LRA has been started

  2. only one participant has joined it since Trip has bot been invoked

Demo 3: destination NOK

From holiday Swagger UI:

  1. Reset the customer id value to 42

  2. Change the destination to "Londonx"

  3. Execute it.

The request has been rejected by Trip with a business error "Rejected destination Londonx".

With Jaeger GUI you can check that:

  1. A LRA has been started

  2. 2 participants have joined it

  3. It has been canceled

Check the consistency of the Trip entity:

  1. get the trip_id value of the response in Holiday Swagger UI

  2. go to Trip Swagger UI and select "find by id"

  3. the status should be REJECTED.

Demo 4: max price exceeded

From holiday Swagger UI:

  1. Reset the destination value to "London"

  2. Change the value of people_count to 2

  3. Execute it

The request has been rejected by Holiday with a business error "Max pricing exceeded".

With Jaeger GUI you can check that:

  1. A LRA has been started

  2. 2 participants have joined it

  3. It has been canceled

Check the consistency of the Trip entity:

  1. Get the trip_id value of the response in Holiday Swagger UI

  2. Switch to Trip Swagger UI and select "find by id"

  3. The status should be CANCELED.

Demo 5: Trip timeout

From Holiday Swagger UI:

  1. Select "Let’s go to Dublin" from the examples

  2. Execute it.

This example illustrates that the compensate method can be run concurrently to the book method for the LRA in some circunstances. Here is what happens:

  • Holiday is configured with a timeout of 1 sec when invoking Trip (see application.properties)

  • When the destination is DUBLIN, Trip sleeps 1.5 sec before answering

  • Holiday cancels the LRA after 1 sec

  • The LRA is canceled while Trip is still processing the request

  • When the Trip compensate method is called, it does not find any request with the given LRA id.

The code has been enforced to tackle this issue:

  • If no business request with the given LRA id has been found when compensating, a database record is stored in a dedicated "compensated_lra" table

  • Before returning, the book method checks whether the LRA has already been canceled by reading this table. If yes, the status switch to CANCELED.

Demo 6: LRA timeout

From Holiday Swagger UI:

  1. Select "Let’s go to Budapest" from the examples

  2. Execute it.

This example illustrates what happens in case of LRA timeout:

  • The LRA is configured with a time limit of 2 seconds on Holiday (see HolidayResource.java)

  • When the destination is BUDAPEST, Holiday sleeps 3 sec at the end of the book method before answering (see HolidayService.java)

  • The LRA is canceled by the lra-coordinator while Holiday is still in the book method and after Trip has accepted the booking

  • When the Holiday compensate method is called, it does not find any request with the given LRA id.

The code has been enforced to tackle this issue:

  • If no business request with the given LRA id has been found by Holiday when compensating, a database record is stored in a dedicated "compensated_lra" table

  • Before returning, the book method checks whether the LRA has already been canceled by reading this table. If yes, the status switch to CANCELED

  • Trip also set the book status to CANCELED when receiving the compensate request.

Testing the annotations

The LRA specification is based on annotations and defines precisely how to use them. Any error is detected at deployment time.

It is possible to test the annotations before by running (on holiday or trip):

mvn test

The test is based on maven-plugin-lra-annotations provided by Narayana (declared in pom.xml).

For example, if you forget to declare a @Compensate method, you get an error message similar to this one:

The class annotated with org.eclipse.microprofile.lra.annotation.ws.rs.LRA missing at least one of the annotations Compensate or AfterLRA Class: io.jefrajames.lrademo.holiday.boundary.HolidayResource

Running in native mode

Holiday can be built and run in native mode:

  1. mvn compile -Pnative to build

  2. ./target/holiday-1.0-runner to run.

Performance consideration

How long is the overhead of a Long Running Action?

Let’s measure it concretly by running the same business logic with and without LRA.

Side note: all figures provided below have been measured in JVM (vs native) mode on my laptop.

Let’s clearly define a starting point without LRA. You can run "Book a Holiday without LRA" from Swagger UI. This is exactly the same business logic but no LRA is used to ensure data consistency. The average response time for a successful request is around 25 msec (see book_response_time field provided in the response).

In the same condition, with LRA, the average response time is 60msec (see lra_response_time field by Finding all holidays from Swagger UI ).

Thus the average overhead of a LRA in that context is around 35msec (+57%).

This result just provides an indication, it is not a real benchmark:

  1. it has been run on a laptop

  2. all components running locally

  3. without any concurrency and multi-threading

  4. the business logic is very simple

  5. Narayana (acting as LRA-Coordinator) has been run without any tuning.

So do not forget to run your own benchmark before going in production!

How does it compare with Eventuate SAGA? In the same condition, the average response time is around 240 msec. That’s significantly higher but should be subject to significant improvement (in particular by tuning the CDC component).

Let’s wrap up our findings:

  1. no LRA: 25 msec

  2. with LRA: 60 msec

  3. with Eventuate SAGA: 240 msec

Warning: these results just provide an indication and should not be taken for granted. There are potentially numerous ways to fine tune these solutions in production.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages