How to build transactional microservice ecosystems with Atomikos: if you want to split-up your monolith then this is how you take care of the integrity of your databases…

The problem

So you're splitting up that monolith into smaller scoped microservices. Then you suddenly realise that what used to be one transaction is now split across multiple processes. It's not easy to make multiple updates across multiple processes and guarantee consistent commit or rollback in case of failures. So what can you do?

The solution

Based on popular demand, we at Atomikos have come up with a solution to manage distributed transactions across separate REST microservices. You can now have atomic, consistent commit or rollback spanning multiple microservice processes with ExtremeTransactions. We support two different types of transactional clients: thin, hypermedia REST clients like JavaScript applications that only do pure REST calls, and backend enterprise Java applications that access their own database in addition to making outbound REST calls.

Let's discuss each scenario in turn:

Thin client scenario

Screenshot 2017-09-29 17.12.19.png

In the thin client scenario, the following happens:

  1. The thin client starts a transaction by calling our RestTransactionService, obtaining a transaction token containing the id and timeout of the transaction.
  2. The thin client now calls the inventory service and passes along the transaction token information in HTTP headers. The inventory microservice "joins" the client's transaction thanks to smart JAX-RS interceptors (more on that below) and performs its work. It returns a URI/URL where its pending transaction work can be committed or rolled back.
  3. Same thing for the payment service…
  4. The client collects the microservice URLs and decides to commit (or rollback) the transaction and calls the RestTransactionService with all URLs involved. The RestTransactionService takes care of 2-phase commit.

Enterprise Java client scenario

Screenshot 2017-10-01 11.02.21.png

In this case, there is no need for a separate RestTransactionService: the client application itself uses an instance of ExtremeTransactions and can use / export its transactions to the external REST services. This means that starting and committing a transaction now happen inside the client's application, and commit includes any external REST services' work.

JAX-RS interceptors

Extending the transaction scope across microservice calls is done via JAX-RS "filters" that intercept incoming and outgoing requests and responses, adding / extracting the necessary information to / from the HTTP headers of the request. Here's how to configure this in your code:

Client-side interceptors

   import com.atomikos.rest.jaxrs.TransactionAwareRestClientFilter;

   javax.ws.rs.client.Client paymentClient = ClientBuilder.newClient();
   paymentClient.register(TransactionAwareRestClientFilter.class);

The client interceptor automatically detects any active Atomikos transaction in the client JVM and propagates it in the outgoing calls via HTTP headers - so the server on the other end can extract and join that transaction. It also extracts any URLs from the response headers for committing the work of the other end as part of the active transaction.

Server-side interceptors

   import com.atomikos.rest.jaxrs.TransactionAwareRestContainerFilter;
   import com.atomikos.rest.jaxrs.AtomikosRestPort;

   JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean(); //we used CXF for our demo
   sf.setProvider(new TransactionAwareRestContainerFilter());
   sf.setResourceProvider(new SingletonResourceProvider(new AtomikosRestPort()));

The server interceptor detects any transaction propagation in the incoming calls - so it can join that transaction. It also adds HTTP headers to the response, containing a URL to commit its work as part of the transaction of the caller. The AtomikosRestPort listens on the URL and awaits commit requests.

Spring REST interceptors

We have similar interceptors for Spring REST, if you prefer that framework over JAX-RS.

Constraint

The only constraint is that all Atomikos instances involved use the same LogCloud recovery node. This maximises recovery guarantees even if individual services go down. Did we mention that it's nearly impossible to kill the LogCloud process?

In practice, this means that you will have managed "clusters" of microservices, where a cluster is defined as the set of microservices that are participating in the same transactions. Each such cluster will have a shared LogCloud instance.

Benefits

Some of the benefits of this technology include:

  • Consistent commit or rollback is now possible across different microservices.
  • If you call a service and get no response (or an exception) then you know it has not committed anything.
  • If you refactor your architecture towards microservices then you don't have to worry so much about consistency.

Try for yourself

This post describes real, working examples of our commercial code base. It's only available to paying customers but we do offer a free trial if you're serious about REST transactions and would like to try for yourself.

Are you serious about REST transactions? Apply here for a free trial!

  • Get on-boarded fast - no need to wait for paperwork
  • Evaluate the full set of power functionality exclusive to customers
  • Avoid late risks by upgrading to the real thing today - so you're all configured to go live without stress
  • No rush or hard deadlines - pay only when you're ready to go live

Tell us about yourself

Name
Email
Phone
Company
Industry
Timing
Please specify the timeframe in which you would be going live with your project.

Apply

Our privacy policy is brief and clear: we do not share your details with anybody. Plus, we'll send you relevant content (only).

Contact Us

Atomikos Corporate Headquarters
Hoveniersstraat, 39/1, 2800
Mechelen, Belgium

E info@atomikos.com
E sales@atomikos.com
T +3215613055

Subscribe to our newsletter

Never miss an update

Copyright 2017 Atomikos BVBA