Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/psamim/narayana-ruby

Use Narayana Transaction Manager in Ruby via REST
https://github.com/psamim/narayana-ruby

Last synced: about 1 month ago
JSON representation

Use Narayana Transaction Manager in Ruby via REST

Awesome Lists containing this project

README

        

#+LATEX_CLASS: assignment
#+OPTIONS: toc:nil
#+TITLE: Transaction Management Using Narayana In Ruby
#+AUTHOR: Samim Pezeshki

* Introduction
This application is a demo for using JBoss Narayana as a transaction manager in Ruby
via Narayana REST API (rts subsystem).
There are two transaction types implemented, nested and chained.
The whole environment and application is packaged into Docker containers.

* Requirements
- docker
- docker-compose

* Installing and Running
#+BEGIN_SRC sh
$ docker-compose up
#+END_SRC

#+LATEX: \vspace{2mm}

The first time, this may take a long time as we need to download Ruby base image, PostgreSQL and Wildfly application server and
build the application. Descriptions about each Docker container is available at =docker-compose.yml= file.

* Description
Narayana transaction manager is a part of Wildfly application server and can be used via its REST API When =rts=
subsystem is enabled in Wildfly. Documentation about how =rts= API works and interacts is available at [[http://narayana.io/docs/project/index.html#d0e15500]].

There were no implementation of Narayana API client in Ruby so I created it. Communication
with Narayana is done through =narayana/transaction= class and HTTP requests. It can create a new transaction,
enlist new participants and put or retrieve the transaction status.

Here is a sample code of how to use =Transaction= class.

#+LATEX: \vspace{2mm}

#+BEGIN_SRC ruby
tx = Transaction.new # Asks for a new transaction on Wildfly
tx.participate @resource # Enlists resource in transction
tx.status # TransactionActive
tx.commit # Puts new status (TransactionCommitted) to Narayana for this transaction
#+END_SRC
#+LATEX: \vspace{2mm}

I created a /Task/ model using =DataMapper= ORM, and created the /Task/ resource using =Sinatra= to respond to
API calls from Wildfly server according to Narayana documentation. Each task can be type of /Chained/ or /Nested/.
Chained tasks can have one /next/ and one /prev/ task. When a chained task is commited, its next task is
triggered. If one chained task fails, itself and its /prev/ are rolled back.

Nested tasks can have multiple /childs/. When a nested task is commited, all of its children are triggered and commited in one
transaction, all or none.

Using this Task model, we can test our transaction manager. Here is a sample code.

Chained transactions:

#+LATEX: \vspace{2mm}

#+BEGIN_SRC ruby
t1 = CheindTask.create
t2 = CheindTask.create

# Creating a chain
t1.next = t2
t1.save

t1.commit # Commits t1 and then t2
#+END_SRC

#+LATEX: \vspace{2mm}

Nested transactions:

#+LATEX: \vspace{2mm}

#+BEGIN_SRC ruby
t1 = NestedTask.create
t2 = NestedTask.create
t3 = NestedTask.create fails: true

# Creating nested transaction
t1.childs << t2 # Add t2 to childs
t1.childs << t3
t1.save

t1.commit # Commits t1, then t2 and t3 in one transaction
#+END_SRC
#+LATEX: \vspace{2mm}

Two sample scenarios are tested as a client in the =app/client.rb= file, one chained transaction and one nested.
These scenarios are run in a separate process called =client=. Also we have another process called =service= which
is our server talking to Narayana API on Wildfly server. All interactions are logged to console. A sample log
file is provided with the source code in =sample.log=. Here is an example log.

[[./screenshot.png]]

The first column says that logs are from the Ruby container or Narayana container. The second column shows
the name of the process, client or service.

* Transaction Results
The results can be seen in the log file or reproduced by running the application.

The first scenario is a nested transaction as picture below. Transaction 4 aborts.
As a result the root is commited, all siblings of T4 are rolled back, because they were in a transaction. Othere are not triggered
because their parent has aborted.

#+CAPTION: Nested Transaction
#+ATTR_LATEX: :width 8cm
[[./nested.png]]

The second scenario is a chained transaction as picture below. C2 aborts.
Chain stops. C2 and its previous tasks should be rolled back in reverse order.
Its next transaction is not triggered.

#+CAPTION: Chained Transaction
#+ATTR_LATEX: :width 8cm
[[./chained.png]]

* Technical Details
The whole application is in Ruby programming language. It uses =Sinatra= and =Rack= for serving the API client.
It uses =DataMapper= as ORM for creating the Task model. =PostgreSQL= is used as our database for storing tasks.

The processes are described in the file =Procfile= and are managed by =foreman= to run as daemons.
Each line in the =Procfile= describes one process of the application.

* Docker Images
The application uses four docker images, postgres, wildfly-rts, dnsdock and ruby.
The Ruby image is the main image
for our application which is built by the provided =Dockerfile=. These images are in the public Docker hub registry
and are downloaded and built automatically by the above command on the first time. The image dnsdock is used a DNS server
between containers so that they can find each other.

These images are configured and run using =docker-compose=. The configuration is in the =docker-compose.yml= file.