tag:blogger.com,1999:blog-86865787244583353262024-03-16T18:53:14.906+00:00Narayana team blogThis is the blog site for the Narayana team. Expect postings on our transaction projects, but also on general transaction issues.Mark Littlehttp://www.blogger.com/profile/15072917010265365428noreply@blogger.comBlogger183125tag:blogger.com,1999:blog-8686578724458335326.post-82562214705887621312023-09-06T09:46:00.003+01:002023-09-06T09:46:58.118+01:00<h1 id="recap-of-recent-narayana-releases">A Review of Recent Narayana Releases</h1>
<p>The last four releases of Narayana have brought some noteworthy changes, closing 86 issues in the process, which I’d like to summarise in this brief post. The contributions have come from both the broader community and the core Narayana team, thank you for that. The changes include bug fixes, dependency upgrades and tasks and features.</p>
<h2 id="community">Community</h2>
<h3 id="improve-inclusiveness-by-building-a-community-of-users">Improve inclusiveness by building a community of users</h3>
<p>We reviewed our <a href="https://issues.redhat.com/browse/JBTM-3715">existing guidance</a>, adding clarifying text to the <a href="https://github.com/jbosstm/narayana/blob/main/CONTRIBUTING.md#contributing-guide">contributing guide</a> and added a SECURITY.md file. The latest snapshot adds an email address for <a href="https://github.com/jbosstm/narayana/blob/main/SECURITY.md#reporting-of-cves-and-security-issues">reporting security issues</a>.</p>
<h3 id="conscious-language">Conscious Language</h3>
<p>We also <a href="https://issues.redhat.com/browse/JBTM-3718">reviewed our materials</a> to ensure that we use welcoming language, free from offensive, othering, or otherwise problematic communication styles.</p>
<h2 id="new-additionsfeatures">New Additions/Features</h2>
<p>All maven modules were migrated from Java EE to Jakarta EE (which included the main narayana repo plus the quickstart, jboss-transaction-spi and performance repos).</p>
<p>There is now a BOM for narayana (<a href="https://issues.redhat.com/browse/JBTM-3735">JBTM-3735</a>). To depend on the correct versions in your projects just include the following dependency:</p>
<pre><code> <dependency>
<groupId>org.jboss.narayana</groupId>
<artifactId>narayana-bom</artifactId>
<version>latest version</version>
<type>pom</type>
<scope>import</scope>
</dependency></code></pre>
<p>The new license for Narayana is <a href="https://github.com/jbosstm/narayana/blob/7.0.0.Final/LICENSE">Apache License 2.0</a>, it replaces LGPL and provides consumers with more flexibility when releasing their own software products that incorporate Narayana (<a href="https://issues.redhat.com/browse/JBTM-3764">JBTM-3764</a>).</p>
<p>Issue <a href="https://issues.redhat.com/browse/JBTM-3734">JBTM-3734</a> was resolved by a community contributor, it introduced support for <a href="https://openjdk.org/jeps/444">JEP-444: Virtual Threads</a>. Virtual threads “dramatically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications”. The change replaced many occurrences of the <code>synchronized</code> java keyword with <a href="https://devdocs.io/openjdk~11/java.base/java/util/concurrent/locks/reentrantlock">ReentrantLock</a> which in most usages, but not all, should be semantically equivalent. The change is an API breaking change so we released the update in a major version, <a href="https://github.com/jbosstm/narayana/releases/tag/7.0.0.Final">7.0.0.Final</a>.</p>
<h2 id="removal-of-features">Removal of features</h2>
<p>All modules have been migrated to Jakarta EE and Java EE is not supported.</p>
<p>Release <a href="https://github.com/jbosstm/narayana/releases/tag/6.0.0.Final">6.0.0.Final</a> removed the transformed Jakarta maven modules (ones that ended in “-jakarta”).</p>
<p>The OSGi module is no longer available, please refer to <a href="https://issues.redhat.com/browse/JBTM-3717">the issue</a> for the reason why this decision was made.</p>
<p>Quickstarts showing integration of <a href="https://issues.redhat.com/browse/JBTM-3747">Spring and Tomcat with Narayana</a> have been temporarily disabled because at the time of the Jakarta migration, Tomcat and Spring had not yet added Jakarta support to their offerings. Issue JBTM-3803 was created for them to be re-enabled when Jakarta variants become available.</p>
<h2 id="long-running-actions-for-microprofile-lra">Long Running Actions for MicroProfile (LRA)</h2>
<p>Release <a href="https://github.com/jbosstm/narayana/releases/tag/6.0.0.Final">6.0.0.Final</a> was <a href="https://github.com/jbosstm/narayana/blob/main/certifications/lra/microprofile-lra-2.0/README.adoc">certified</a> against MicroProfile LRA 2.0.</p>
<p>We added a Narayana specific <a href="https://issues.redhat.com/browse/JBTM-3755">feature</a> to allow LRA participants to store data with the <a href="https://jbossts.blogspot.com/2021/07/narayana-lra-update.html">coordinator</a> (3rd section) during the registration phase. The feature is configurable, using the <a href="https://microprofile.io/specifications/microprofile-config/">MicroProfile Config</a> approach, because some users may prefer not to entrust their business data with the coordinator.</p>
<p>The bug fix for <a href="https://issues.redhat.com/browse/JBTM-3749">JBTM-3749</a> facilitated <a href="https://www.wildfly.org/news/2023/05/24/MicroProfile-LRA/">the integration of LRA into WildFly</a>, LRA support in WildFly was added with issue <a href="https://issues.redhat.com/browse/WFLY-14869">WFLY-14869</a> by Martin Stefanko, an active contributor to LRA. JBTM-3749 provided a partial fix for <a href="https://issues.redhat.com/browse/JBTM-3552">JBTM-3552</a> (Do not rely on thread locals for propagating LRA context) and it also included a <a href="https://www.narayana.io//docs/project/index.html#d5e7531">doc update</a> recommending that users explicitly set the LRA context when JAX-RS resource methods perform outgoing JAX-RS invocations.</p>
<p>The latest snapshot of narayana includes documentation about configuring the <a href="https://github.com/jbosstm/narayana/blob/main/rts/lra/README.adoc">concurrency of the LRA coordinator start method</a>, the details are in issue <a href="https://issues.redhat.com/browse/JBTM-3753">JBTM-3753</a>.</p>
<h2 id="transaction-logging">Transaction Logging</h2>
<p>Transaction managers log data in order to provide the <a href="https://en.wikipedia.org/wiki/Durability_(database_systems)">Durability</a> property of a transactions. Narayana supports a variety of persistence stores, including logging to a database which we call the JDBCStore. <a href="https://issues.redhat.com/browse/JBTM-3724">JBTM-3724</a> included a quickstart for this store and <a href="https://issues.redhat.com/browse/JBTM-3754">JBTM-3754</a> introduced an option to supply the DataSource for connecting to the store at runtime for use with the Quarkus extension for <a href="https://quarkus.io/guides/transaction#jdbcstore">JTA transactions</a>.</p>
Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-36566571949377192252022-04-21T18:05:00.001+01:002022-04-25T17:04:27.316+01:00Narayana on the Cloud - Part 1<p style="text-align: left;"><span style="font-family: arial;">In the last few months, I have been working on how distributed transactions are recovered in WildFly when this Application Server (AS) is deployed in Kubernetes. This blog post is a reflection on how Narayana performs on the cloud and the features it is still missing for it to evolve into a native cloud transaction suite.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">Some (very brief) context</span></h3><p style="text-align: left;"><span style="font-family: arial;">Narayana started its journey more than 30 years ago! ArjunaCore was developed in the late 1980s. Even though the theoretical concept of cloud computing was introduced by John McCarthy in 1961 [1][2], at the time of ArjunaCore’s development it was still considered only as a theoretical possibility. However, in the past two decades, the implementation of cloud computing has increased exponentially, dramatically changing the world of technology. As a consequence, Narayana (and its ArjunaCore) needs to step up its game to become a cloud native transaction suite that can be used in different cloud environments. This is an ongoing conversation the Narayana team has started a long time ago (for a detailed summary of Narayana's Cloud Strategy see [3]).</span></p><p style="text-align: left;"><span style="font-family: arial;">Narayana was introduced to the cloud through WildFly (note 1) on Kubernetes (K8s). In my recent experience, I worked on WildFly and its K8s operator [4] and I think that the integration between Narayana and WildFly works very smoothly on K8s [5]. On the other hand, when the pod hosting WildFly needs to scale down, the ephemeral nature of K8s does not get along with Narayana very well. In fact, ArjunaCore/Narayana needs to have a stable ground to perform its magic (within or without WildFly). In particular, Narayana needs to have:</span></p><ul style="text-align: left;"><li><span style="font-family: arial;">A stable and durable Object Store where objects’ states are held</span><span style="font-family: arial;"> </span></li><li><span style="font-family: arial;">A stable node identifier to uniquely mark transactions (which are initialised by the Transaction Manager (TM) with the same node identifier) and ensure that the Recovery Manager will only recover those transactions </span></li><li><span style="font-family: arial;">A stable communication channel to allow participants of transactions to communicate with the TM</span></li></ul><p style="text-align: left;"><span style="font-family: arial;">In all points above, “stable” indicates the ability to survive whatever happens to the host where Narayana is running (e.g., crashes). On the other hand, K8s is an ephemeral environment where pods do not need a stable storage and/or particular configurations that survive over multiple reboots. To overcome this “incompatibility”, K8s provides StatefulSet [6] through which applications can leverage a stable realm. Particularly in relation to Narayana, the employment of StatefulSet and the addition of a transaction recovery module to the WildFly K8s Operator [7] enables this AS to fully support transactions on K8s. Unfortunately, this solution is tailor-made for K8s and it cannot be easily ported in other cloud environments. Our <b>target</b>, though, is to evolve Narayana to become a cloud transaction suite, which means that Narayana should also support other cloud computing infrastructures.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">Our take on this</span></h3><p style="text-align: left;"><span style="font-family: arial;">The </span><span style="font-family: arial;"><span style="font-family: arial;">Narayana</span> team thoroughly discussed the above limitations that prevent Narayana from becoming a native cloud application. A brief summary is presented here:</span></p><ul style="text-align: left;"><li><i><b><span style="font-family: arial;">A stable and durable Object Store where objects’ states are held</span></b></i><span style="font-family: arial;"><br />Narayana is able to use different kinds of object stores; in particular, it is possible to use a (SQL) database to create the object store [8]. RDBMS databases are widely available on cloud environments: these solutions already cover our stability needs providing a reliable storage solution that supports replications and that is able to scale up on demand. Moreover, using a “centralised” RDBMS database would easen the management of multiple Narayana instances, which can be connected to the same database. This might also become incredibly useful in the future when it comes to evolving Narayana to work with multiple instances behind a load balancer (i.e. in case of replication)</span><span style="font-family: arial;"> </span></li><li><i><b><span style="font-family: arial;">A stable communication channel to allow participants of transactions to communicate with the TM</span></b></i><span style="font-family: arial;"><i><br /></i>Most cloud providers (and platforms) already offer two options to tackle this problem: a stable IP address and a DNS. Although both methods still need some tweaking for each cloud provider, these solutions should provide a stable endpoint to communicate with Narayana’s TM over multiple reboots</span><span style="font-family: arial;"> </span></li><li><i><b><span style="font-family: arial;">A stable node identifier to uniquely mark transactions (which are initialised by the Transaction Manager (TM) with the same node identifier) and ensure that the Recovery Manager will only recover those transactions</span></b></i><span style="font-family: arial;"><br />This is the actual sticky point this blog post is about. Although it seems straightforward to assign a unique node identifier to the TM, it is indeed the first real logic challenge to solve on the path to turn Narayana in a <i><b>cloud</b></i> transaction manager</span><br /></li></ul><p style="text-align: left;"><span style="font-family: arial;">We discussed different possible solutions to this last point but we are still trying to figure out how to address this issue. The main problem is that Narayana needs stable storage to save the node identifier and reload it after a reboot. As already said, cloud environments do not provide this option very easily as their ephemeral nature is more inclined to a stateless approach. Our first idea to solve this problem was, “<i>why do we not store the node identifier in the object store? Narayana still needs a stable object store (and this constraint cannot be dropped) and RDBMS databases on the cloud already provide a base to start from</i>”. The node identifier is a property of the transaction manager that gets initialised when Narayana/ArjunaCore starts (together with all the other properties). As a consequence, it is not possible to save the node identifier in the object store as the preferences for the object store are also loaded during the same initialisation process! In other words, if the node identifier is stored in the object store, how can Narayana/ArjunaCore know where the object store is without loading all properties? Which came first: the chicken or the egg? Nevertheless, introducing an order when properties are loaded might help in this regard (i.e. we force the egg to exist before the chicken). Nevertheless, there is still a problem: what happens if the object store is shared between different instances of Narayana/ArjunaCore? For example, it might be very likely that a Narayana administrator configures multiple Narayana instances to create their object stores in the same database. In this case, every Narayana instance would need a unique identifier to tell which node identifier in the object store is its own. Recursive problems are fun :-) Even if we solve all these problems, the assignment of the node identifier should not be possible outside of Narayana (e.g. using system properties) and it should become an exclusive (internal) operation of Narayana. Fortunately, this is easier than solving our previous “chicken and egg” problem as there are solutions to generate a (almost) unique distributed identifier locally [9]. As things stand, we should find an alternative solution to port the node identifier to the cloud.</span></p><p style="text-align: left;"><span style="font-family: arial;">Looking at this problem from a different point of view, I wonder if there are more recent solutions to replace and/or remove the node identifier from Narayana. With this in mind, the first question I ask myself is “<i><b>Why do we need a node identifier?</b></i>”. Behind the hood, Narayana uses a recovery manager to try to recover transactions that have not completed their lifecycle. This comes with a caveat though: it is essential that two different recovery managers do not try to recover the same in-doubt transaction at the same time. That is where the node identifier comes in handy! In fact, thanks to the unique node identifier (that gets embedded in every global transaction identifier), the recovery manager can recognise if it is responsible for the recovery of an in-doubt transaction stored in a remote resource (note 2). This concept is best illustrated by an example. Let’s consider two different Narayana instances that initiate two different transactions that enlist the same resource. In this scenario, both transaction managers store a record in the shared resource. Let’s assume that the first Narayana instance starts the transaction before the second instance. While the first transaction gets to the point where it has sent <i>prepare()</i> to its enlisted resources, it is possible that the recovery manager of the second Narayana instance queries the shared resource for in-doubt records. If Narayana’s recovery manager was not forced to recover only transactions initiated by the same Narayana instance’s TM, this hypothetical scenario would have ended with an error: the recovery manager of the second Narayana instance would have rolled back the transaction initiated by the first Narayana instance, assuming that it was one of its own in-doubt transaction!</span></p><p style="text-align: left;"><span style="font-family: arial;">Cloud environments are encouraging (all of) us to come up with an innovative solution to reduce the footprint of Narayana/ArjunaCore. In particular, the node identifier is the challenge we are currently facing and the first real step to push Narayana onto the cloud. I will share any updates the Narayana team comes up with…and in the meantime, feel free to reach out to the team through our public channels (for example Gitter or our Google group narayana-users) to propose your ideas or discuss with us your take on this fundamental issue.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">Note</span></h3><ol style="text-align: left;"><li><span style="font-family: arial;">WildFly supports transactions thanks to the integration with Narayana</span></li><li><span style="font-family: arial;">It is possible to tell the Recovery Manager that it will be responsible for the recovery of in-doubt transactions initiated by different transaction managers (which are identified with different node identifiers). The only caveat here is that two Recovery Managers should not recover the same in-doubt transaction at the same time. To assign the responsibility of multiple node identifiers to the same Recovery Manager, the property xaRecoveryNodes [10] in Narayana’s JTAEnvironmentBean should be used.<br /></span></li></ol><h3 style="text-align: left;"><span style="font-family: arial;">Bibliography</span></h3><p style="text-align: left;"><span style="font-family: arial;">[1] J. Surbiryala and C. Rong, "Cloud Computing: History and Overview," 2019 IEEE Cloud Summit, 2019, pp. 1-7, doi: 10.1109/CloudSummit47114.2019.00007.</span></p><p style="text-align: left;"><span style="font-family: arial;">[2] Garfinkel, Simson L. and Harold Abelson. “Architects of the Information Society: 35 Years of the Laboratory for Computer Science at Mit.” (1999).</span></p><p style="text-align: left;"><span style="font-family: arial;">[3] https://jbossts.blogspot.com/2022/03/narayana-community-priorities.html</span></p><p style="text-align: left;"><span style="font-family: arial;">[4] https://github.com/wildfly/wildfly-operator</span></p><p style="text-align: left;"><span style="font-family: arial;">[5] https://issues.redhat.com/browse/EAP7-1394</span></p><p style="text-align: left;"><span style="font-family: arial;">[6] https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/</span></p><p style="text-align: left;"><span style="font-family: arial;">[7] https://github.com/wildfly/wildfly-operator/</span></p><p style="text-align: left;"><span style="font-family: arial;">[8] https://www.narayana.io/docs/project/index.html#d0e459</span></p><p style="text-align: left;"><span style="font-family: arial;">[9] https://groups.google.com/g/narayana-users/c/ttSff9HvXdA</span></p><p style="text-align: left;"><span style="font-family: arial;">[10] https://www.narayana.io//docs/product/index.html#d0e1032 <br /></span></p>Manuel Finellihttp://www.blogger.com/profile/09407487982873134227noreply@blogger.com0Newcastle upon Tyne NE4 5TG, UK54.9732327 -1.624427554.972616915670827 -1.6255003836059569 54.973848484329167 -1.6233546163940429tag:blogger.com,1999:blog-8686578724458335326.post-89131798805977793002022-03-04T13:24:00.002+00:002022-03-04T13:24:18.139+00:00Narayana Community Priorities<h1>Narayana Community Priorities</h1>
<p>The following is an outline of our near term priorities for the Narayana open source transaction manager.
They have been set based on input from the community, including the narayana-users <a href="https://groups.google.com/g/narayana-users/c/xOUAQPTdPVg">forum discussion</a>.</p>
<p>It is not necessarily a complete list, so please continue to share your own thoughts on whether you agree they are the right focus for the project, in some respects the list is quite ambitious and we encourage/need and welcome continued contributions and discussion from the community to help achieve these goals.</p>
<h2>Community Engagement</h2>
<ol>
<li>Improve inclusiveness by building a community of users:
<ul>
<li>produce clear guidance on how to contribute with different levels of guidance</li>
<li>responsive to the community (PRs, queries, issues, rooms etc)</li>
<li>issue labels for new contributors and for tasks that we need help with</li>
<li>make sure all new features are publicised (blog, articles, docs, etc)</li>
<li>regular blog posts with runnable and focused examples</li>
<li>acknowledge contributors in release announcements</li>
<li>encourage discussions in the community (i.e. minimise private team discussions)</li>
</ul>
</li>
</ol>
<h2>Java Versions</h2>
<ol>
<li><a href="https://issues.redhat.com/browse/JBTM-3588">Support native JTA 2.0, EE 10 and Jakarta EE namespace</a>: this work is already well under way.
Java SE 11 is now the minimum runtime supported by WildFly and Jakarta EE compatible implementations.</li>
<li><a href="https://issues.redhat.com/browse/JBTM-3590">Remove support for Java SE 8</a> (i.e. SE 11 will the minimum supported version) and add <a href="https://issues.redhat.com/browse/JBTM-3482">support for Java SE 17</a></li>
</ol>
<h2>Integrating contemporary services:</h2>
<ol>
<li><a href="https://issues.redhat.com/browse/JBTM-3586">Kafka Integration</a></li>
<li><a href="https://github.com/quarkusio/quarkus/issues/15364">Quarkus support for REST-AT</a>.
This task depends on <a href="https://issues.redhat.com/browse/JBTM-3457">SRA (aka REST-AT annotations) Tasks</a></li>
</ol>
<h2>Cloud strategy:</h2>
<ol>
<li><a href="https://issues.redhat.com/browse/JBTM-3587">Managed Transaction Service</a></li>
<li>An improved cloud strategy for JTA around recovery (again we have already started work in this area). Currently we need to create a bespoke solution for every cloud, e.g. the <a href="https://github.com/wildfly/wildfly-operator/blob/master/doc/user-guide.adoc#scaledown-transaction-recovery">WildFly kubernetes operator</a>.
This task includes provision of a more “cloud ready” transaction log store.
The task still needs to be pinned down but some relevant input material includes:
<ol>
<li><a href="https://issues.redhat.com/browse/JBTM-1451">Transactional cloud resources</a> (this includes an investigation of whether an Infinispan based store is feasible - note that earlier versions were incompatible with our needs)</li>
<li><a href="https://issues.redhat.com/browse/JBTM-2411">Investigate jgroups-raft and whether this can help with creating a cloud-ready object store</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-312">Add clustering support</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-2116">Add an SPI nethod to obtain a unique identifier for a transaction</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-2827">No easy way to acquire the node name from the JBoss Transaction SPI</a></li>
</ol>
<p>There is also the forum item: <a href="https://groups.google.com/g/narayana-users/c/ttSff9HvXdA">reliably generate node identifiers</a> which will help with using Narayana in cloud deployments:</p>
<ul>
<li>the task should also explore the pros and cons of storing it for crash recovery purposes</li>
<li>the forum thread also includes some work that we may do on validating our current uid solution for cloud environments</li>
</ul>
</li>
<li>Better integration of LRA in cloud environments:
<ol>
<li><a href="https://issues.redhat.com/browse/JBTM-2997">Ensure that any LRA coordinator instance can control any LRA</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-2959">Allow different LRA coordinators to share an object store</a></li>
</ol>
</li>
</ol>
<h2>Transaction Log Stores</h2>
<ol>
<li>Persistent Memory: narayana already provides a pmem based object store which we would like to <a href="https://github.com/wildfly/wildfly-proposals/pull/446">integrate into WildFly</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-3589">Journal Store performance improvements</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-1761">Provide a native file lock alternative</a> to our own Object Store locking (FileLock.java) for managing concurrent access to a transaction log.
It should be configurable at runtime or build time (Quarkus is a good use case). If the runtime platform does not provide the capability then a default fallback mechanism will be defined.</li>
</ol>
<h2>Upgrades/Deprecation/Removal/Replacement of existing functionality:</h2>
<ol>
<li>Remove <a href="https://narayana.io//docs/project/index.html#d0e3208">Transactional Driver</a> in favour of using <a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.3/html/configuration_guide/datasource_management_agroal">Agroal</a>. We are tracking this work using <a href="https://issues.redhat.com/browse/JBTM-3439">JBTM-3439</a>.</li>
<li>Remove <a href="https://github.com/jbosstm/narayana/tree/5.12.5.Final/txframework">txframework</a> - it was previously deprecated by the <a href="https://github.com/jbosstm/narayana/tree/5.12.5.Final/compensations">compensations module</a>. The issue tracker is <a href="https://issues.redhat.com/browse/JBTM-2221">Remove old TXFramework API</a></li>
<li><a href="https://issues.redhat.com/browse/JBTM-3577">Remove support for JacORB which is now EOL</a></li>
<li>Upgrade to JUnit 5 (from 4) for unit testing: <a href="https://issues.redhat.com/browse/JBTM-3483">Testing Narayana using JUnit 5</a></li>
</ol>
<h2>Other</h2>
<ol>
<li>Improved support for asynchronous APIs. Although we continue to be tied to XA and very few resource managers support the asynchronous component of the <a href="https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf">XA spec section 3.5 Synchronous, Non-blocking and Asynchronous Modes</a>, there are still things we would like to do in this area including <a href="https://issues.redhat.com/browse/JBTM-2475">Asynchronous JTA</a></li>
</ol>
Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-1261483424753262762022-01-05T13:26:00.000+00:002022-01-05T13:26:12.025+00:00Securing LRA endpoints using JWT<p><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;"></span></p><h2 id="_introduction" style="background-color: white; color: #666666; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative;">Introduction</h2><p><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;"><b>JWT</b> stands for <b>JSON Web Token</b>, which is a popular way to do user authorization in web application and is also popular in the context of micro-services. So, when we use <b>Long Running Actions</b> (<b>LRA</b>) in any micro-service, the transaction APIs could be authorized using JWT tokens. Open industry standard specification </span><a href="https://datatracker.ietf.org/doc/html/rfc7519" style="color: #e3a833; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;">RFC-7519</a><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;"> outlines how JTW is structured and how to use it. JWT works over <i>HTTP protocol</i>. The reason JWT is now a days preferred more is because it makes the authorization mechanism easier for micro-service applications, avoids single point of failure and also helps the application design to be more scalable.</span></p><p><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;">Here is how JWT is structured: [</span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: red; font-size: 13.2px;"><HEADER></span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;">.</span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 13.2px;"><PAYLOAD></span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;">.</span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #2b00fe; font-size: 13.2px;"><SIGNATURE></span><span style="background-color: white; color: #666666; font-size: 13.2px;">]</span></p><p><span style="color: #666666;"><span style="background-color: white;"><span style="font-size: 13.2px;">The JWT token is divided into three parts, as we can see in the above example which are separated by two periods.</span></span></span></p><pre style="background-color: white; color: #666666; font-size: 13.2px;"><tt><span style="color: black;"><span> </span>1:</span> HEADER -> base64UrlEncode(header)
<span style="color: black;"> 2:</span> PAYLOAD -> base64UrlEncode(payload)
<span style="color: black;"> 3:</span> SIGNATURE -> encryptionAlgorithm(</tt>base64UrlEncode(header) + '.' + base64UrlEncode(payload),256-bit-SECRET)</pre><pre style="background-color: white; color: #666666; font-size: 13.2px;"><span style="font-family: "Times New Roman"; font-size: 13.2px; white-space: normal;">You can create your own JWT token by visiting website </span><a href="https://jwt.io/" style="background-color: transparent; color: #e3a833; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;">jwt.io</a>.<span style="font-family: "Times New Roman"; font-size: 13.2px; white-space: normal;"> JWT is a value token, which will only contain the user information in PAYLOAD, with the name of type of algorithm used in the HEADER and the token verification signature in the SIGNATURE part.</span></pre><pre style="background-color: white; color: #666666; font-size: 13.2px;"><span style="font-family: Times New Roman;"><span style="white-space: normal;"><br /></span></span><span style="font-family: "Times New Roman"; font-size: 13.2px; white-space: normal;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjyA0D7i6bJNEb4-h6JKXdM_wQ7O4VWYMfBeRm3PApRzxD4oa0niVoZGtxcuTLLhapXg12mKA1eLQSRzLERQR_-Tn8mZ1a9d0UTY19yWJ86p-cddq0vYYBScPpod0yLUPi_jkj-Y7xqwDZ6nwSxl7vol_r_u_TUDJKiK7QIKKze1rPriTSyMHDnlkM=s665" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="470" data-original-width="665" height="226" src="https://blogger.googleusercontent.com/img/a/AVvXsEjyA0D7i6bJNEb4-h6JKXdM_wQ7O4VWYMfBeRm3PApRzxD4oa0niVoZGtxcuTLLhapXg12mKA1eLQSRzLERQR_-Tn8mZ1a9d0UTY19yWJ86p-cddq0vYYBScPpod0yLUPi_jkj-Y7xqwDZ6nwSxl7vol_r_u_TUDJKiK7QIKKze1rPriTSyMHDnlkM=s320" width="320" /></a></div><br /></span></pre><pre style="background-color: white; color: #666666; font-size: 13.2px;"><span style="font-family: "Times New Roman"; font-size: 13.2px; white-space: normal;">The above figure shows the implication of JWT. The server will create JWT token and will give it to the client, so that client can send it back on the subsequent request. Once the JWT token is created and provided to the client, we can do a REST call to as below:</span></pre><pre style="background-color: white; color: #666666;"><span style="font-family: "Times New Roman"; font-size: 13.2px; white-space: normal;"> curl -H "Authorization:Bearer [</span><span style="font-size: x-small;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: red;"><HEADER></span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #666666;">.</span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #ff00fe;"><PAYLOAD></span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #666666;">.</span><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #2b00fe;"><SIGNATURE></span>]" http://127.0.0.1:8080/app/api</span></pre><h2 id="_introduction" style="background-color: white; color: #666666; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative;">Securing LRA endpoints</h2><p><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;">There are various LRA annotations used, which will internally call the REST APIs that are present in </span><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L128" style="color: #e3a833; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;">Coordinator</a> <span style="background-color: white; color: #666666; font-size: 13.2px;">and </span><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L60" style="color: #e3a833; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;">RecoveryCoordinator</a> <span style="background-color: white; color: #666666; font-size: 13.2px;">classes. So, below are the recommendations to, how to define <b>roles</b> for each and every APIs in order to create JWT token for client.</span></p><p><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #666666; font-size: 13.2px;"></span></p><table class="styled-table" style="background-color: white; border-collapse: collapse; box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 20px; color: #666666; font-family: sans-serif; font-size: 0.9em; margin: 25px 0px; min-width: 400px;"><thead><tr style="background-color: #fff2db; color: black;"><th style="padding: 12px 15px;"><span style="font-size: 14.4px;">LRA-endPoints</span></th><th style="padding: 12px 15px;">Allowed-roles</th><th style="padding: 12px 15px;"><br /></th></tr></thead><tbody><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L175"><span style="color: #e69138;">getAllLRAs</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L212"><span style="color: #e69138;">getLRAStatus</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L245"><span style="color: #e69138;">getLRAInfo</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L288"><span style="color: #e69138;">startLRA</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L372"><span style="color: #e69138;">renewTimeLimit</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="getNestedLRAStatus"><span style="color: #e69138;">getNestedLRAStatus</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L468"><span style="color: #e69138;">closeLRA</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L496"><span style="color: #e69138;">cancelLRA</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L542"><span style="color: #e69138;">joinLRAViaBody</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L675"><span style="color: #e69138;">leaveLRA</span></a></td><td style="padding: 12px 15px;">client</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L421"><span style="color: #e69138;">completeNestedLRA</span></a></td><td style="padding: 12px 15px;">system</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L427"><span style="color: #e69138;">compensateNestedLRA</span></a></td><td style="padding: 12px 15px;">system</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/Coordinator.java#L433"><span style="color: #e69138;">forgetNestedLRA</span></a></td><td style="padding: 12px 15px;"><span style="font-size: 14.4px;">system</span></td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L84"><span style="color: #e69138;">getCompensator</span></a></td><td style="padding: 12px 15px;">admin</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L116"><span style="color: #e69138;">replaceCompensator</span></a></td><td style="padding: 12px 15px;">admin</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L156"><span style="color: #e69138;">getRecoveringLRAs</span></a></td><td style="padding: 12px 15px;">admin</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr><tr style="border-bottom: 1px solid rgb(221, 221, 221);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L169"><span style="color: #e69138;">getFailedLRAs</span></a></td><td style="padding: 12px 15px;">admin</td><td style="padding: 12px 15px;"><br /></td></tr><tr style="background-color: #f3f3f3; border-bottom: 2px solid rgb(255, 214, 143);"><td style="padding: 12px 15px;"><a href="https://github.com/jbosstm/narayana/blob/master/rts/lra/coordinator/src/main/java/io/narayana/lra/coordinator/api/RecoveryCoordinator.java#L189"><span style="color: #e69138;">deleteFailedLRA</span></a></td><td style="padding: 12px 15px;">admin</td><td style="padding: 12px 15px;"><code><br /><br /></code></td></tr></tbody></table><p><span style="background-color: white; color: #666666; font-size: 13.2px;">One of the popular tool that could be used to generate JWT tokens would be </span><a href="https://developers.redhat.com/blog/2020/01/29/api-login-and-jwt-token-generation-using-keycloak#" style="color: #e3a833; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;">Keycloak</a><span style="background-color: white; font-size: 13.2px;"><span style="color: #666666;">. Keycloak is an open source identity and access management solution. For more details about Keycloak you can also visit </span><a href="https://www.keycloak.org/"><span style="color: #e69138;">keycloak.org</span></a></span><span style="background-color: white; color: #666666; font-size: 13.2px;">.</span></p><h2 id="_introduction" style="background-color: white; color: #666666; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative;">Problems with JWT and their solutions</h2><div><br /></div><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><b>1.</b> Anyone can read first two parts of JWT tokens, i.e. HEADER and PAYLOAD, which are only base64 encoded. So, the PAYLOAD part must not contain any confidential information. It should contain enough information so that server could know who the user is.</span></div><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><br /></span></div><div><span style="background-color: white; font-size: 13.2px;"><b style="color: #666666;">2.</b><span style="color: #666666;"> If someone steals your JWT token, it will work for anyone. So in order to avoid the theft, we should be careful about how we are transmitting JWT. It has to be HTTPS connection and by using the process of </span><b><a href="https://en.wikipedia.org/wiki/OAuth"><span style="color: #e69138;">OAuth</span></a></b><span style="color: #666666;"> which comes with its own security and protection to make sure people don't steal JWT tokens.</span></span></div><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><br /></span></div><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><b>3. </b>In compare to session based authentication, if someone steals sessionID, we can log off, which ends the session and it doesn't exist anymore. But in case of JWT there is nothing on the server to end. Since the whole information is inside JWT, we only set expiration for JWT by having expiry PAYLOADs, but we cannot log off. This situation can be handled by creating blacklisted JWTs table at server side and when the request comes to server, that JWT token will be validated if not the blacklisted one then the server will authorize the request if the token had valid signature.</span></div><p><span style="background-color: white; color: #666666; font-size: 13.2px;"></span></p><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><b>4. </b>If we choose to use <i>Expiry JWT token</i> for LRA, then if the transaction did not complete before the token expiration, then transaction will never complete. So avoid using <i>Expiry JWT tokens</i> with LRA and try to follow above three ways in order to avoid the security breaches.</span></div><div><span style="background-color: white; color: #666666; font-size: 13.2px;"><br /></span></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-51845520818980390832021-08-17T11:56:00.007+01:002021-08-17T12:21:31.871+01:00LRA annotation checker Maven plugin<style>
.styled-table {
border-collapse: collapse;
margin: 25px 0;
font-size: 0.9em;
font-family: sans-serif;
min-width: 400px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
}
.styled-table thead tr {
background-color: #fff2db;
color: #000;
text-align: left;
}
.styled-table th,
.styled-table td {
padding: 12px 15px;
}
.styled-table tbody tr {
border-bottom: 1px solid #dddddd;
}
.styled-table tbody tr:nth-of-type(even) {
background-color: #f3f3f3;
}
.styled-table tbody tr:last-of-type {
border-bottom: 2px solid #ffd68f;
}
.styled-table tbody tr.active-row {
font-weight: bold;
color: #009879;
}
</style>
<p>
With the release of the LRA (<i>Long Running Actions</i>) specification in <a href="https://github.com/eclipse/microprofile-lra/releases/tag/1.0">version 1.0</a>
Narayana team works on integrating the <a href="https://github.com/jbosstm/narayana/tree/master/rts/lra">Narayana implementation</a>
to various application runtimes. Currently it's
<a href="https://github.com/quarkusio/quarkus/pull/17903">Quarkus</a> and <a href="https://github.com/wildfly/wildfly-proposals/pull/398">WildFly</a>. (<i>Camel is a third platform
<a href="https://camel.apache.org/components/latest/others/lra.html">integrating the Narayana implementation</a> but it does in a way not depending on LRA annotations
defined in the specification.</i>).
</p>
<p>
<i>NOTE:</i>
If you want to get introduction what is LRA and what is good for you can read some of the
already published articles (<a href="https://jbossts.blogspot.com/2021/07/how-to-use-long-running-actions-between.html">1</a>,
<a href="https://jbossts.blogspot.com/2017/12/narayana-lra-implementation-of-saga.html">2</a>).
</p>
<p>
At this time when the LRA can be easily grab and used within the application runtimes
it may come <b>some difficulty on precise use</b> of
the <a href="https://github.com/eclipse/microprofile-lra/tree/master/api/src/main/java/org/eclipse/microprofile/lra/annotation">LRA annotations</a>.
</p>
<p>
The <a href="https://github.com/eclipse/microprofile-lra/blob/1.0/spec/src/main/asciidoc/microprofile-lra-spec.adoc#starting-and-ending-lras">specification</a>
defines different "requirements" the LRA application has to follow to work correctly. Some are basic as
<i>"the LRA annotated class must contain at least one of the methods annotated with <code>@Compensate</code> or <code>@AfterLRA</code>"</i>
or <i>that the LRA annotated JAX-RS endpoints has predefined HTTP methods to be declared with</i>.
For example the
<code><a href="https://github.com/eclipse/microprofile-lra/blob/1.0/api/src/main/java/org/eclipse/microprofile/lra/annotation/Complete.java">@Complete</a>/<a href="https://github.com/eclipse/microprofile-lra/blob/1.0/api/src/main/java/org/eclipse/microprofile/lra/annotation/Compensate.java">@Compensate</a></code>
requires the <code>@PUT</code> method while the
<a href="https://github.com/eclipse/microprofile-lra/blob/1.0/api/src/main/java/org/eclipse/microprofile/lra/annotation/Forget.java"><code>@Forgot</code></a>
requires the <code>@DELETE</code> and
<a href="https://github.com/eclipse/microprofile-lra/blob/1.0/api/src/main/java/org/eclipse/microprofile/lra/annotation/Status.java"><code>@Status</code></a>
requires the <code>@GET</code>.
</p>
<p>
When the specific <b>LRA contract rule is violated</b> the developer will find them at the deployment time
with the
<code><a hre="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/RuntimeException.html">RuntimeException</a></code>
being thrown.
But time of the deployment could be a bit late to find just a forgotten
annotation required by the LRA specification.
With that idea in mind Narayana offers a Maven plugin project
<a href="https://github.com/jbosstm/incubator/tree/master/lra-annotation-checker">Narayana LRA annotation checker</a>.
</p>
<p>
The developer working with the LRA introduces the dependency to the LRA annotation
with artifact
<code><a href="https://search.maven.org/artifact/org.eclipse.microprofile.lra/microprofile-lra-api/1.0/jar">org.eclipse.microprofile.lra:microprofile-lra-api:1.0</a></code>.
He codes the application and then he can introduce the Maven plugin of the LRA checker
to be run during Maven phase <code>process-classes</code>.
The developer needs to point to the plugin goal <code>check</code> to get the verification being run.
</p>
<p>
The snippets that can be placed to the project <code>pom.xml</code> is following.
The plugin Maven artifact coordinates is <b>io.narayana:maven-plugin-lra-annotations_1.0:1.0.0.Beta1</b><br/>
</p>
<pre style="font-size:90%"><code class="java">...
<build>
<plugins>
<plugin>
<groupId>io.narayana</groupId>
<artifactId>maven-plugin-lra-annotations_1.0</artifactId>
<version>1.0.0.Beta1</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...</code></pre>
<p>
When plugin is loaded it searches for classes available at path <code>${project.build.directory}/classes</code>
(i.e., <code>target/classes</code>) and tries to find if the application preserve the rules
defined by the LRA specification.
When not then the Maven build fails reporting what error happens.<br/>
Such an error is in format of <code>[error id]:[description]</code>.
Example of <a href="https://github.com/jbosstm/artifacts/tree/master/jbossts.blogspot/17-08-2021-lra-annotation-checker">such error</a> is
</p>
<pre style="font-size:70%; white-space: pre-wrap; ">
[ERROR] Failed to execute goal io.narayana:maven-plugin-lra-annotations_1.0:1.0.0.Beta1:check (default) on project lra-annotation-checker-maven-plugin-test: LRA annotation errors:
[ERROR] [[4]]->
1: The class annotated with org.eclipse.microprofile.lra.annotation.ws.rs.LRA missing at least one of the annotations Compensate or AfterLRA Class: io.narayana.LRAParticipantResource;
2: Multiple annotations of the same type are used. Only one per the class is expected. Multiple annotations 'org.eclipse.microprofile.lra.annotation.Status' in the class 'class io.narayana.LRAParticipantResource' on methods [status, status2].;
4: Wrong method signature for non JAX-RS resource method. Signature for annotation 'org.eclipse.microprofile.lra.annotation.Forget' in the class 'io.narayana.LRAParticipantResource' on method 'forget'. It should be 'public void/CompletionStage/ParticipantStatus forget(java.net.URI lraId, java.net.URI parentId)';
5: Wrong complementary annotation of JAX-RS resource method. Method 'complete' of class 'class io.narayana.LRAParticipantResource' annotated with 'org.eclipse.microprofile.lra.annotation.Complete' misses complementary annotation javax.ws.rs.PUT.
</pre>
<p>
The plugin can be configured with two parameters (placed under <code><configuration></code>
under the <code><plugin></code> element).
</p>
<table class="styled-table">
<thead>
<tr>
<th>Attribute</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td>paths</td>
<td>Paths searched for classes to be checked. Point to a directory or jar file. Multiple paths are delimited with a comma.</td>
<td><code>${project.build.directory}/classes</code></td>
</tr>
<tr>
<td>failWhenPathNotExist</td>
<td>When some path defined within argument <code>paths</code> does not exist
then Maven build may fail or resume with information that the path is not available.</td>
<td><code>true</code></td>
</tr>
</tbody>
</table>
<p>
All the points described in this article can be seen and tested in an example at
<a href="https://github.com/jbosstm/artifacts/blob/master/jbossts.blogspot/17-08-2021-lra-annotation-checker">github.com/jbosstm/artifacts#jbossts.blogspot/17-08-2021-lra-annotation-checker</a>.
The plugin configuration can be seen in the
<a href="https://github.com/jbosstm/artifacts/blob/master/jbossts.blogspot/17-08-2021-lra-annotation-checker/pom.xml">pom.xml</a>
of the same project.
</p>
<p>
Any comments, ideas for enhancement and bug reports are welcomed.
The project LRA annotation checker Maven plugin is placed in the
<a href="https://github.com/ochaloup/incubator/tree/master/lra-annotation-checker"><code>jbosstm</code> incubator repository</a>.
The issues can be submitted via JBTM issue tracker at
<a href="https://issues.jboss.org/browse/JBTM">https://issues.jboss.org/browse/JBTM</a>.
</p>
<p>
Hopefully this small plugin provides a better experience for any developer
working with the LRA and LRA Narayana implementation in particular.
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-87062022175353811322021-07-20T21:31:00.002+01:002021-08-17T12:18:31.184+01:00How to use Long Running Actions between microservices<div id="header">
</div>
<div id="content">
<div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph"><p>In my <a href="https://jbossts.blogspot.com/2021/07/narayana-lra-update.html">last post</a> I showed how to run a Long Running Action (LRA) within a single JAX-RS resource method using quarkus features to build and run the application. I showed how to create and start an LRA coordinator and then generated a basic <code>hello</code> application, showing how to modify the application to run with a long running action (by adding dependencies on the <code>org.eclipse.microprofile.lra:microprofile-lra-api</code> and <code>org.jboss.narayana.rts:narayana-lra</code> artifacts, which together provide annotations for controlling the lifecycle of LRAs). That post also includes links to the <a href="https://download.eclipse.org/microprofile/microprofile-lra-1.0-M1/microprofile-lra-spec.html">the LRA specification</a> and to the <a href="https://download.eclipse.org/microprofile/microprofile-lra-1.0/apidocs/">javadoc for the annotation API</a>.</p></div>
<div class="paragraph"><p>In this follow up post I will indicate how to include a second resource in the LRA. To keep things interesting I’ll deploy the second resource to another microservice and use quarkus’s MicroProfile Rest Client support to implement the remote service invocations. The main difference between this example and the one I developed in the earlier post, apart from the technicalities of using Rest Client, is that we will set the <a href="https://download.eclipse.org/microprofile/microprofile-lra-1.0/apidocs/org/eclipse/microprofile/lra/annotation/ws/rs/LRA.html#end--">LRA.end</a> attribute to <code>false</code> in the remote service so that the LRA will remain active when the call returns. In this way the initiating service method has the option of calling other microservices before ending the LRA.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_creating_and_starting_an_lra_coordinator">Creating and starting an LRA coordinator</h2>
<div class="sectionbody">
<div class="paragraph"><p>LRA relies on a coordinator to manage the lifecycle of LRAs so you will need one to be running for this demo to work successfully.
The <a href="https://jbossts.blogspot.com/2021/07/narayana-lra-update.html">previous post</a> showed how to build and run coordinators. Alternatively, <a href="https://github.com/jbosstm/artifacts/tree/master/jbossts.blogspot/21-07-2021">download or view some scripts</a> which execute all of the steps required in the current post and it includes a shell script called <a href="https://github.com/jbosstm/artifacts/blob/master/jbossts.blogspot/21-07-2021/coordinator.sh">coordinator.sh</a> which will build a runnable coordinator jar (it’s fairly simple and short so you can just read it and create your own jar or just run it as is).</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_generate_a_project_for_booking_tickets">Generate a project for booking tickets</h2>
<div class="sectionbody">
<div class="paragraph"><p>Since the example will be REST based, include the <code>resteasy</code> and <code>rest-client</code> extensions (on line 6 next):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> mvn io.quarkus:quarkus-maven-plugin:2.0.1.Final:create \
<span style="color: #000000"> 2:</span> -DprojectGroupId=org.acme \
<span style="color: #000000"> 3:</span> -DprojectArtifactId=ticket \
<span style="color: #000000"> 4:</span> -DclassName="org.acme.ticket.TicketResource" \
<span style="color: #000000"> 5:</span> -Dpath="/tickets" \
<span style="color: #000000"> 6:</span> -Dextensions="resteasy,rest-client"
<span style="color: #000000"> 7:</span> cd ticket</tt></pre></div></div>
<div class="paragraph"><p>You will need the <code>mvn</code> program to run the plugin (but the generated projects will include the <code>mvnw</code> maven wrapper).</p></div>
<div class="paragraph"><p>Modify the generated <code>TicketResource.java</code> source file to add Microprofile LRA support. The changes that you will need for LRA are on lines 26 and 27. Line 26 says that the <code>bookTicket</code> method must run with an LRA (if one is not present when the method is invoked then one will be automatically created). Note that we have set the <code>end</code> attribute to false to stop the LRA from being automatically closed when the method finishes. By keeping the LRA active when the ticket is booked, the caller can invoke other services in the context of the same LRA. Most services will require the LRA context for tracking updates which typically will be useful for knowing which actions to compensate for if the LRA is later cancelled: the context is injected as a JAX-RS method parameter on line 27.</p></div>
<div class="paragraph"><p>You will also need to include callbacks for when the LRA is later closed or cancelled (the methods are defined on lines 37 and line 46, respectively).</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> <span style="font-weight: bold"><span style="color: #000080">package</span></span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>ticket<span style="color: #990000">;</span>
<span style="color: #000000"> 2:</span>
<span style="color: #000000"> 3:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="font-weight: bold"><span style="color: #0000FF">static</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>MediaType<span style="color: #990000">.</span>APPLICATION_JSON<span style="color: #990000">;</span>
<span style="color: #000000"> 4:</span>
<span style="color: #000000"> 5:</span> <span style="font-style: italic"><span style="color: #9A1900">// import annotation definitions</span></span>
<span style="color: #000000"> 6:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">;</span>
<span style="color: #000000"> 7:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Compensate<span style="color: #990000">;</span>
<span style="color: #000000"> 8:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Complete<span style="color: #990000">;</span>
<span style="color: #000000"> 9:</span> <span style="font-style: italic"><span style="color: #9A1900">// import the definition of the LRA context header</span></span>
<span style="color: #000000"> 10:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="font-weight: bold"><span style="color: #0000FF">static</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">.</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">;</span>
<span style="color: #000000"> 11:</span>
<span style="color: #000000"> 12:</span> <span style="font-style: italic"><span style="color: #9A1900">// import some JAX-RS types</span></span>
<span style="color: #000000"> 13:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>GET<span style="color: #990000">;</span>
<span style="color: #000000"> 14:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>PUT<span style="color: #990000">;</span>
<span style="color: #000000"> 15:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Path<span style="color: #990000">;</span>
<span style="color: #000000"> 16:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Produces<span style="color: #990000">;</span>
<span style="color: #000000"> 17:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>Response<span style="color: #990000">;</span>
<span style="color: #000000"> 18:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>HeaderParam<span style="color: #990000">;</span>
<span style="color: #000000"> 19:</span>
<span style="color: #000000"> 20:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/tickets"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 21:</span> @<span style="font-weight: bold"><span style="color: #000000">Produces</span></span><span style="color: #990000">(</span>APPLICATION_JSON<span style="color: #990000">)</span>
<span style="color: #000000"> 22:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> <span style="color: #008080">TicketResource</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 23:</span>
<span style="color: #000000"> 24:</span> @GET
<span style="color: #000000"> 25:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/book"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 26:</span> @<span style="font-weight: bold"><span style="color: #000000">LRA</span></span><span style="color: #990000">(</span>value <span style="color: #990000">=</span> LRA<span style="color: #990000">.</span>Type<span style="color: #990000">.</span>REQUIRED<span style="color: #990000">,</span> end <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span><span style="color: #990000">)</span> <span style="font-style: italic"><span style="color: #9A1900">// an LRA will be started before method execution if none exists and will not be ended after method execution</span></span>
<span style="color: #000000"> 27:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">bookTicket</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 28:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TicketResource.bookTicket: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 29:</span> <span style="color: #008080">String</span> ticket <span style="color: #990000">=</span> <span style="color: #FF0000">"1234"</span>
<span style="color: #000000"> 30:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">(</span>ticket<span style="color: #990000">).</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 31:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 32:</span>
<span style="color: #000000"> 33:</span> <span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA closes:</span></span>
<span style="color: #000000"> 34:</span> @PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
<span style="color: #000000"> 35:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/complete"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 36:</span> @Complete
<span style="color: #000000"> 37:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">completeWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 38:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TicketResource.completeWork: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 39:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 40:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 41:</span>
<span style="color: #000000"> 42:</span> <span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA cancels:</span></span>
<span style="color: #000000"> 43:</span> @PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
<span style="color: #000000"> 44:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/compensate"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 45:</span> @Compensate
<span style="color: #000000"> 46:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">compensateWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 47:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TicketResource.compensateWork: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 48:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 49:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 50:</span> <span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>Skip the tests:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>rm src/test/java/org/acme/ticket<span style="color: #990000">/*</span></tt></pre></div></div>
<div class="paragraph"><p>Add dependencies on <code>microprofile-lra-api</code> and <code>narayana-lra</code> to the pom to include the MicroProfile LRA annotations and the narayana implementation of them so that the LRA context will be propagated during interservice communications:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt> <span style="font-weight: bold"><span style="color: #0000FF"><dependencies></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.eclipse.microprofile.lra<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>microprofile-lra-api<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>1.0<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.jboss.narayana.rts<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>narayana-lra<\/artifactId>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>5.12.0.Final<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span></tt></pre></div></div>
<div class="paragraph"><p>We are creating ticket and trip microservices so they need to listen on different ports, configure the ticket service to run on port <code>8081</code>:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> quarkus<span style="color: #990000">.</span>arc<span style="color: #990000">.</span>exclude-types<span style="color: #990000">=</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>client<span style="color: #990000">.</span>internal<span style="color: #990000">.</span>proxy<span style="color: #990000">.</span>nonjaxrs<span style="color: #990000">.</span>LRAParticipantRegistry<span style="color: #990000">,</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>filter<span style="color: #990000">.</span>ServerLRAFilter<span style="color: #990000">,</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>client<span style="color: #990000">.</span>internal<span style="color: #990000">.</span>proxy<span style="color: #990000">.</span>nonjaxrs<span style="color: #990000">.</span>LRAParticipantResource
<span style="color: #000000"> 2:</span> quarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span><span style="color: #009900">port</span><span style="color: #990000">=</span><span style="color: #993399">8081</span>
<span style="color: #000000"> 3:</span> quarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span>test-port<span style="color: #990000">=</span><span style="color: #993399">8081</span></tt></pre></div></div>
<div class="paragraph"><p>The excludes are pulled in by the <code>org.jboss.narayana.rts:narayana-lra</code> maven dependency. As mentioned in my previous post this step will not be necessary when the pull request for the <code>io.quarkus:quarkus-narayana-lra</code> extension is approved.
Now build and test the ticket service, making sure that you have already started a coordinator as described in the previous blog (or you can use the shell scripts <a href="#Creating and starting an LRA coordinator">linked above</a>):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">.</span>/mvnw clean package -DskipTests <span style="font-style: italic"><span style="color: #9A1900"># skip tests</span></span>
java -jar target/quarkus-app/quarkus-run<span style="color: #990000">.</span>jar <span style="color: #990000">&</span> <span style="font-style: italic"><span style="color: #9A1900"># run the application in the background</span></span>
curl http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8081</span>/tickets/book
TicketResource<span style="color: #990000">.</span>bookTicket<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_2
<span style="color: #993399">1234</span></tt></pre></div></div>
<div class="paragraph"><p>The <code>bookTicket()</code> method prints the method name and the id of the active LRA followed by the hard-coded booking id <code>1234</code>.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_generate_a_project_for_booking_trips">Generate a project for booking trips</h2>
<div class="sectionbody">
<div class="paragraph"><p>Now create a second microservice which will be used for booking trips. It will invoke other microservices to complete trip bookings. In order to simplify the example there is just the single remote ticket service involved in the booking process.</p></div>
<div class="paragraph"><p>First generate the project. Like the ticket service, the example will be REST based so include the <code>resteasy</code> and <code>rest-client</code> extensions:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>mvn io.quarkus:quarkus-maven-plugin:2.0.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=trip \
-DclassName="org.acme.trip.TripResource" \
-Dpath="/trips" \
-Dextensions="resteasy,rest-client"
cd trip</tt></pre></div></div>
<div class="paragraph"><p>The <code>rest-client</code> extension includes support for MicroProfile REST Client which we shall use to perform the remote REST invocations from the trip to the ticket service. For REST Client we need a <code>TicketService</code> and we need to register it as shown on line 12 of the following listing:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> <span style="font-weight: bold"><span style="color: #000080">package</span></span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>trip<span style="color: #990000">;</span>
<span style="color: #000000"> 2:</span>
<span style="color: #000000"> 3:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>rest<span style="color: #990000">.</span>client<span style="color: #990000">.</span>inject<span style="color: #990000">.</span>RegisterRestClient<span style="color: #990000">;</span>
<span style="color: #000000"> 4:</span>
<span style="color: #000000"> 5:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>GET<span style="color: #990000">;</span>
<span style="color: #000000"> 6:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Path<span style="color: #990000">;</span>
<span style="color: #000000"> 7:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Produces<span style="color: #990000">;</span>
<span style="color: #000000"> 8:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>MediaType<span style="color: #990000">;</span>
<span style="color: #000000"> 9:</span>
<span style="color: #000000"> 10:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/tickets"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 11:</span> @<span style="font-weight: bold"><span style="color: #000000">Produces</span></span><span style="color: #990000">(</span>MediaType<span style="color: #990000">.</span>APPLICATION_JSON<span style="color: #990000">)</span>
<span style="color: #000000"> 12:</span> @RegisterRestClient
<span style="color: #000000"> 13:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="font-weight: bold"><span style="color: #0000FF">interface</span></span> <span style="color: #008080">TicketService</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 14:</span>
<span style="color: #000000"> 15:</span> @GET
<span style="color: #000000"> 16:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/book"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 17:</span> <span style="color: #008080">String</span> <span style="font-weight: bold"><span style="color: #000000">bookTicket</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 18:</span> <span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>Let’s also create a <code>TripService</code> and inject an instance of the <code>TicketService</code> into it, marking it with the <code>@RestClient</code> annotation on line 11. The quarkus rest client support will configure this injected instance such that it will perform remote REST calls to the ticket service (the remote endpoint for the ticket service will be configured below in the <code>application.properties</code> file):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> <span style="font-weight: bold"><span style="color: #000080">package</span></span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>trip<span style="color: #990000">;</span>
<span style="color: #000000"> 2:</span>
<span style="color: #000000"> 3:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>rest<span style="color: #990000">.</span>client<span style="color: #990000">.</span>inject<span style="color: #990000">.</span>RestClient<span style="color: #990000">;</span>
<span style="color: #000000"> 4:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>enterprise<span style="color: #990000">.</span>context<span style="color: #990000">.</span>ApplicationScoped<span style="color: #990000">;</span>
<span style="color: #000000"> 5:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>inject<span style="color: #990000">.</span>Inject<span style="color: #990000">;</span>
<span style="color: #000000"> 6:</span>
<span style="color: #000000"> 7:</span> @ApplicationScoped
<span style="color: #000000"> 8:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> <span style="color: #008080">TripService</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 9:</span>
<span style="color: #000000"> 10:</span> @Inject
<span style="color: #000000"> 11:</span> @RestClient
<span style="color: #000000"> 12:</span> <span style="color: #008080">TicketService</span> ticketService<span style="color: #990000">;</span>
<span style="color: #000000"> 13:</span>
<span style="color: #000000"> 14:</span> <span style="color: #008080">String</span> <span style="font-weight: bold"><span style="color: #000000">bookTrip</span></span><span style="color: #990000">()</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 15:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> ticketService<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">bookTicket</span></span><span style="color: #990000">();</span> <span style="font-style: italic"><span style="color: #9A1900">// only one service will be used for the trip booking</span></span>
<span style="color: #000000"> 16:</span>
<span style="color: #000000"> 17:</span> <span style="font-style: italic"><span style="color: #9A1900">// if other services need to be part of the trip they would be called here</span></span>
<span style="color: #000000"> 18:</span> <span style="font-style: italic"><span style="color: #9A1900">// and the TripService would associate each step of the booking with the id of the LRA</span></span>
<span style="color: #000000"> 19:</span> <span style="font-style: italic"><span style="color: #9A1900">// (although I've not shown it being passed in this example) and that would form the</span></span>
<span style="color: #000000"> 20:</span> <span style="font-style: italic"><span style="color: #9A1900">// basis of the ability to compensate or clean up depending upon the outcome.</span></span>
<span style="color: #000000"> 21:</span> <span style="font-style: italic"><span style="color: #9A1900">// We may include a more comprehensive/realistic example in a later blog.</span></span>
<span style="color: #000000"> 22:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 23:</span> <span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>And now we can inject an instance of this service into the generated TripResource (<code>src/main/java/org/acme/trip/TripResource.java</code>) on line 26. I have also annotated the <code>bookTrip()</code> method with an LRA annotation so that a new LRA will be started before the method is started (if one wasn’t already present) and I have added <code>@Complete</code> and <code>@Compensate</code> callback methods (these will be called when the LRA closes or cancels, respectively):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> <span style="font-weight: bold"><span style="color: #000080">package</span></span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>trip<span style="color: #990000">;</span>
<span style="color: #000000"> 2:</span>
<span style="color: #000000"> 3:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>inject<span style="color: #990000">.</span>Inject<span style="color: #990000">;</span>
<span style="color: #000000"> 4:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>GET<span style="color: #990000">;</span>
<span style="color: #000000"> 5:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Path<span style="color: #990000">;</span>
<span style="color: #000000"> 6:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>Produces<span style="color: #990000">;</span>
<span style="color: #000000"> 7:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>Response<span style="color: #990000">;</span>
<span style="color: #000000"> 8:</span>
<span style="color: #000000"> 9:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="font-weight: bold"><span style="color: #0000FF">static</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>MediaType<span style="color: #990000">.</span>APPLICATION_JSON<span style="color: #990000">;</span>
<span style="color: #000000"> 10:</span>
<span style="color: #000000"> 11:</span> <span style="font-style: italic"><span style="color: #9A1900">// import annotation definitions</span></span>
<span style="color: #000000"> 12:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">;</span>
<span style="color: #000000"> 13:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Compensate<span style="color: #990000">;</span>
<span style="color: #000000"> 14:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Complete<span style="color: #990000">;</span>
<span style="color: #000000"> 15:</span> <span style="font-style: italic"><span style="color: #9A1900">// import the definition of the LRA context header</span></span>
<span style="color: #000000"> 16:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="font-weight: bold"><span style="color: #0000FF">static</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">.</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">;</span>
<span style="color: #000000"> 17:</span>
<span style="color: #000000"> 18:</span> <span style="font-style: italic"><span style="color: #9A1900">// import some JAX-RS types</span></span>
<span style="color: #000000"> 19:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>PUT<span style="color: #990000">;</span>
<span style="color: #000000"> 20:</span> <span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>HeaderParam<span style="color: #990000">;</span>
<span style="color: #000000"> 21:</span>
<span style="color: #000000"> 22:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/trips"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 23:</span> @<span style="font-weight: bold"><span style="color: #000000">Produces</span></span><span style="color: #990000">(</span>APPLICATION_JSON<span style="color: #990000">)</span>
<span style="color: #000000"> 24:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> <span style="color: #008080">TripResource</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 25:</span>
<span style="color: #000000"> 26:</span> @Inject
<span style="color: #000000"> 27:</span> <span style="color: #008080">TripService</span> service<span style="color: #990000">;</span>
<span style="color: #000000"> 28:</span>
<span style="color: #000000"> 29:</span> <span style="font-style: italic"><span style="color: #9A1900">// annotate the hello method so that it will run in an LRA:</span></span>
<span style="color: #000000"> 30:</span> @GET
<span style="color: #000000"> 31:</span> @<span style="font-weight: bold"><span style="color: #000000">LRA</span></span><span style="color: #990000">(</span>LRA<span style="color: #990000">.</span>Type<span style="color: #990000">.</span>REQUIRED<span style="color: #990000">)</span> <span style="font-style: italic"><span style="color: #9A1900">// an LRA will be started before method execution and ended after method execution</span></span>
<span style="color: #000000"> 32:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/book"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 33:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">bookTrip</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 34:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TripResource.bookTrip: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 35:</span> <span style="color: #008080">String</span> ticket <span style="color: #990000">=</span> service<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">bookTrip</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 36:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">(</span>ticket<span style="color: #990000">).</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 37:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 38:</span>
<span style="color: #000000"> 39:</span> <span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA closes:</span></span>
<span style="color: #000000"> 40:</span> @PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
<span style="color: #000000"> 41:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/complete"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 42:</span> @Complete
<span style="color: #000000"> 43:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">completeWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 44:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TripResource.completeWork: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 45:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 46:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 47:</span>
<span style="color: #000000"> 48:</span> <span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA cancels:</span></span>
<span style="color: #000000"> 49:</span> @PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
<span style="color: #000000"> 50:</span> @<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/compensate"</span><span style="color: #990000">)</span>
<span style="color: #000000"> 51:</span> @Compensate
<span style="color: #000000"> 52:</span> <span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">compensateWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="color: #000000"> 53:</span> System<span style="color: #990000">.</span>out<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">printf</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"TripResource.compensateWork: %s%n"</span><span style="color: #990000">,</span> lraId<span style="color: #990000">);</span>
<span style="color: #000000"> 54:</span> <span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #000000"> 55:</span> <span style="color: #FF0000">}</span>
<span style="color: #000000"> 56:</span> <span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>For the blog we can skip the tests:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>rm src/test/java/org/acme/trip<span style="color: #990000">/*</span></tt></pre></div></div>
<div class="paragraph"><p>Configure the trip service to listen on port <code>8082</code> (line 2). Also configure the remote ticket endpoint as required by the MicroProfile REST Client specification (line 5):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #000000"> 1:</span> quarkus<span style="color: #990000">.</span>arc<span style="color: #990000">.</span>exclude-types<span style="color: #990000">=</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>client<span style="color: #990000">.</span>internal<span style="color: #990000">.</span>proxy<span style="color: #990000">.</span>nonjaxrs<span style="color: #990000">.</span>LRAParticipantRegistry<span style="color: #990000">,</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>filter<span style="color: #990000">.</span>ServerLRAFilter<span style="color: #990000">,</span>io<span style="color: #990000">.</span>narayana<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>client<span style="color: #990000">.</span>internal<span style="color: #990000">.</span>proxy<span style="color: #990000">.</span>nonjaxrs<span style="color: #990000">.</span>LRAParticipantResource
<span style="color: #000000"> 2:</span> quarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span><span style="color: #009900">port</span><span style="color: #990000">=</span><span style="color: #993399">8082</span>
<span style="color: #000000"> 3:</span> quarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span>test-port<span style="color: #990000">=</span><span style="color: #993399">8082</span>
<span style="color: #000000"> 4:</span>
<span style="color: #000000"> 5:</span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>trip<span style="color: #990000">.</span>TicketService/mp-rest/url<span style="color: #990000">=</span>http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8081</span>
<span style="color: #000000"> 6:</span> org<span style="color: #990000">.</span>acme<span style="color: #990000">.</span>trip<span style="color: #990000">.</span>TicketService/mp-rest/scope<span style="color: #990000">=</span>javax<span style="color: #990000">.</span>inject<span style="color: #990000">.</span>Singleton</tt></pre></div></div>
<div class="paragraph"><p>Add dependencies on <code>microprofile-lra-api</code> and <code>narayana-lra</code> to the pom to include the MicroProfile LRA annotations and the narayana implementation of them so that the application can request that the LRA context be propagated during interservice communications:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt> <span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.eclipse.microprofile.lra<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>microprofile-lra-api<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>1.0<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.jboss.narayana.rts<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>narayana-lra<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>5.12.0.Final<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span></tt></pre></div></div>
<div class="paragraph"><p>and finally, build and run the microservice:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="color: #990000">.</span>/mvnw clean package -DskipTests
java -jar target/quarkus-app/quarkus-run<span style="color: #990000">.</span>jar <span style="color: #990000">&</span></tt></pre></div></div>
<div class="paragraph"><p>Use <code>curl</code> to book a trip. The HTTP GET request to the <code>trips/book</code> endpoint is handled by the trip service <code>bookTrip()</code> method and it then invokes the <code>ticket</code> service to book a ticket.
When the <code>bookTrip()</code> method finishes the LRA will be closed (since the default value for the <code>LRA.end</code> attribute is <code>true</code>), triggering calls to the service <code>@Complete</code> methods of the two services:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8082</span>/trips/book
TripResource<span style="color: #990000">.</span>bookTrip<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_52c
TicketResource<span style="color: #990000">.</span>bookTrip<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_52c
TripResource<span style="color: #990000">.</span>completeWork<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_52c
TicketResource<span style="color: #990000">.</span>bookTrip<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_52c
TicketResource<span style="color: #990000">.</span>completeWork<span style="color: #990000">:</span> http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_8b2b_60f6a8d4_52c
<span style="color: #993399">1234</span></tt></pre></div></div>
<div class="paragraph"><p>Notice the output shows the bookTrip and bookTicket methods being called and also notice that the <code>@Complete</code> methods of both services (<code>completeWork()</code>) were called.
The <code>id</code> of the LRA on all calls should be the same value as shown in the example output, this is worthwhile noting since the completion and compensation methods will typically use it in order to determine which actions it should clean up for or compensate for when the LRA closes or cancels.</p></div>
<div class="paragraph"><p>Not shown here, but if there was a problem booking the ticket then the ticket service should return a JAX-RS status code (<code>4xx</code> and <code>5xx</code> HTTP codes by default) that triggers the cancellation of the LRA, and this would then cause the <code>@Compensate</code> methods of all services involved in the LRA to be invoked.</p></div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated
2021-07-20 21:25:50 BST
</div>
</div>Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-48634625701360581992021-07-14T11:28:00.001+01:002021-08-17T12:19:56.278+01:00Narayana LRA Update<!--<div id="header">
<h1>Narayana LRA Update</h1>
</div>
-->
<div id="content">
<div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph"><p>This is another in a series of blogs about the compensation based approach to transactions that the team have been producing over the years. The latest such model is LRA (Long Running Actions), originally based on the 2006 OASIS LRA spec, which was recently been <a href="https://projects.eclipse.org/projects/technology.microprofile/releases/lra-1.0">accepted</a> by the Eclipse Foundation. <a href="https://download.eclipse.org/microprofile/microprofile-lra-1.0-M1/microprofile-lra-spec.html">The specification</a> and the <a href="https://download.eclipse.org/microprofile/microprofile-lra-1.0/apidocs/">javadoc for the annotation API</a> are also available.</p></div>
<div class="paragraph"><p>Although LRA is a simple protocol it has a number of interesting features and one blog won’t do it justice. In this, the first one, I will describe how to create a simple microservice that executes in the context of an LRA. Section 1 explains how to create and run an LRA coordinator, section 2 describes how to create and run a participant, and in the final section there is a short review of the many blogs on the subject that the team have created during the past decade. These blogs are an excellent source of wisdom so I will try to avoid repeating old ground and refer the reader to those blogs for the details of the general approach (of which MP-LRA is just the latest incarnation).</p></div>
<div class="paragraph"><p>In follow up blogs the team and I plan to cover, in no particular order:</p></div>
<div class="ulist"><ul>
<li>
<p>
how to participate in failure recovery (including participant, coordinator and network failures)
</p>
</li>
<li>
<p>
writing participants in languages other than Java
</p>
</li>
<li>
<p>
nesting LRA’s to structure business flows (into hierarchies)
</p>
</li>
<li>
<p>
various methods of triggering the cancellation of an LRA (resulting in the reliable invocation all compensation activities)
</p>
</li>
<li>
<p>
leaving LRA’s early
</p>
</li>
<li>
<p>
inspecting the progress of participants
</p>
</li>
<li>
<p>
inspecting failed participants (i.e. ones which have finished in a failed state)
</p>
</li>
<li>
<p>
restarting crashed participants on different endpoints
</p>
</li>
<li>
<p>
show services interacting with each other in different JVMs
</p>
</li>
<li>
<p>
show services running on OpenShift
</p>
</li>
<li>
<p>
leveraging quarkus and WildFly features to simplify the development process (using extensions and galleon feature packs)
</p>
</li>
<li>
<p>
addressing the demands that cloud infrastructures, such as OpenShift, place on LRA’s
</p>
</li>
<li>
<p>
investigate some best practices and future plans for managing the availability of coordinators and participants (including participant storage, different storage types such as databases and journals, and scaling of coordinators)
</p>
</li>
<li>
<p>
strategies for writing compensation logic
</p>
</li>
<li>
<p>
and I’m sure my colleagues will have plenty of other topics to add to this list.
</p>
</li>
</ul></div>
</div>
</div>
<div class="sect1">
<h2 id="_the_example">The Example</h2>
<div class="sectionbody">
<div class="paragraph"><p>A Long Running Action is an interaction between microservices such that all parties (called LRA participants) are guaranteed to be notified when the interaction finishes (in either a successful <code>closing</code> state or an unsuccessful <code>cancelling</code> state). A JAX-RS resource participates in an interaction by marking one or more of its methods with the <code>@LRA</code> annotation and by marking another of its methods with an <code>@Compensate</code> annotation. When a method marked with <code>@LRA</code> is invoked the resource is enlisted in the LRA. Enlisting with an LRA means that if the associated LRA is cancelled then the method annotated with <code>@Compensate</code> is invoked reliably (i.e. it will continue to be called until it is definite that the method executed successfully and that the coordinator received the response). The resource may also request that it be reliably notified if the LRA is closed by marking one of its methods with an <code>@Complete</code> annotation. Note that the LRA id is available to all annotated methods so that all parties know which context is <code>Active</code>.</p></div>
<div class="paragraph"><p>In order to implement the guarantees stated in the previous paragraph, the narayana implementation requires that there are one or more LRA coordinators running in the system. A coordinator runs on behalf of many services and is responsible for starting and ending LRA’s and for managing the participant membership in the LRA, in other words it must be available for an interaction to progress (start, enlist and end). Similarly, participant resources must be available during the end phase of the LRA so they too must be restarted if they fail.</p></div>
<div class="paragraph"><p>Note that the developer is normally unconcerned with the coordinator and a typical installation will run them as part of the platform, freeing up the developer to concentrate on the business of creating microservices. However, for the purposes of the blog, first I’ll indicate how you can create one. Note that there is a similar <a href="https://github.com/jbosstm/quickstart/tree/master/rts/lra-examples/lra-coordinator">example in our quickstart repo</a>. Later on we will make the blog examples available in the same repo.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_starting_a_coordinator">Starting a coordinator</h2>
<div class="sectionbody">
<div class="paragraph"><p>Here we show how to build and run a REST based coordinator from scratch as a java executable using the quarkus framework.</p></div>
<div class="paragraph"><p>The Narayana LRA coordinator is a JAX-RS resource so it needs the quarkus resteasy extension and it needs to depend on the Narayana LRA coordinator implementation.</p></div>
<div class="paragraph"><p>First generate a quarkus application using the <code>quarkus-maven-plugin</code>, specifying the <code>resteasy-jackson</code> and <code>rest-client</code> extensions which pull in everything we need for JAX-RS:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>mvn io<span style="color: #990000">.</span>quarkus<span style="color: #990000">:</span>quarkus-maven-plugin<span style="color: #990000">:</span><span style="color: #993399">2.0</span><span style="color: #990000">.</span><span style="color: #993399">1</span><span style="color: #990000">.</span>Final<span style="color: #990000">:</span>create <span style="color: #990000">\</span>
-DprojectGroupId<span style="color: #990000">=</span>org<span style="color: #990000">.</span>acme <span style="color: #990000">\</span>
-DprojectArtifactId<span style="color: #990000">=</span>narayana-lra-coordinator <span style="color: #990000">\</span>
-Dextensions<span style="color: #990000">=</span><span style="color: #FF0000">"resteasy-jackson,rest-client"</span>
cd narayana-lra-coordinator</tt></pre></div></div>
<div class="paragraph"><p>To obtain coordinator support add the <code>org.jboss.narayana.rts:lra-coordinator-jar:5.12.0.Final</code> maven dependency to the <code>dependencies</code> section of the generated pom.xml file as follows:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt> <span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.jboss.narayana.rts<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>lra-coordinator-jar<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>5.12.0.Final<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span></tt></pre></div></div>
<div class="paragraph"><p>Here I have chosen the latest release (5.12.0.Final) of the Narayana LRA coordinator.
Because we just need the quarkus framework for running the coordinator, remove the generated example: <code>rm -rf src</code>.</p></div>
<div class="paragraph"><p>Now build and start the coordinator on port 8080:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>rm <span style="color: #990000">-</span>rf src
mvn clean <span style="font-weight: bold"><span style="color: #000080">package</span></span>
java <span style="color: #990000">-</span>Dquarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span>port<span style="color: #990000">=</span><span style="color: #993399">8080</span> <span style="color: #990000">-</span><span style="color: #008080">jar</span> target<span style="color: #990000">/</span>quarkus<span style="color: #990000">-</span>app<span style="color: #990000">/</span>quarkus<span style="color: #990000">-</span>run<span style="color: #990000">.</span>jar <span style="color: #990000">&</span></tt></pre></div></div>
<div class="paragraph"><p>If you want to check that the coordinator is running try listing the active LRA’s:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator</tt></pre></div></div>
<div class="paragraph"><p>By default the coordinator stores records in the filesystem in a directory called <code>ObjectStore</code> in the user directory (i.e. the value of the system property <code>user.dir</code>). You can change the location by adding a file called <code>src/main/resources/jbossts-properties.xml</code> with content:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #000080"><!DOCTYPE</span></span> <span style="color: #009900">properties</span> <span style="color: #009900">SYSTEM</span> <span style="color: #FF0000">"http://java.sun.com/dtd/properties.dtd"</span><span style="font-weight: bold"><span style="color: #000080">></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><properties></span></span>
<span style="font-style: italic"><span style="color: #9A1900"><!-- unique id of an LRA coordinator --></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><entry</span></span> <span style="color: #009900">key</span><span style="color: #990000">=</span><span style="color: #FF0000">"CoreEnvironmentBean.nodeIdentifier"</span><span style="font-weight: bold"><span style="color: #0000FF">></span></span>1<span style="font-weight: bold"><span style="color: #0000FF"></entry></span></span>
<span style="font-style: italic"><span style="color: #9A1900"><!-- location of the LRA logs --></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><entry</span></span> <span style="color: #009900">key</span><span style="color: #990000">=</span><span style="color: #FF0000">"ObjectStoreEnvironmentBean.objectStoreDir"</span><span style="font-weight: bold"><span style="color: #0000FF">></span></span>target/lra-logs<span style="font-weight: bold"><span style="color: #0000FF"></entry></span></span>
<span style="font-style: italic"><span style="color: #9A1900"><!-- location of the communications store --></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><entry</span></span> <span style="color: #009900">key</span><span style="color: #990000">=</span><span style="color: #FF0000">"ObjectStoreEnvironmentBean.communicationStore.objectStoreDir"</span><span style="font-weight: bold"><span style="color: #0000FF">></span></span>target/lra-logs<span style="font-weight: bold"><span style="color: #0000FF"></entry></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></properties></span></span></tt></pre></div></div>
<div class="paragraph"><p>You can test the coordinator is operating correctly by trying to create an LRA using <code>curl</code>, for example.</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl -XPOST http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator/start
http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_9471_60ed85da_a</tt></pre></div></div>
<div class="paragraph"><p>Note the id of the new LRA in the output.</p></div>
<div class="paragraph"><p>Now try closing the LRA (include the uid part of the LRA id followed by <code>/close</code>):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl -XPUT http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator<span style="color: #990000">/</span>0_ffffc0a8000e_9471_60ed85da_a/close
Closed</tt></pre></div></div>
<div class="paragraph"><p>You may verify that the coordinator no longer has a record of the LRA:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8080</span>/lra-coordinator
<span style="color: #990000">[]</span></tt></pre></div></div>
<div class="paragraph"><p>The output will be a json array (<code>[]</code>) of the LRA’s that the coordinator is managing. Check that the array does not contain the id of the LRA that you have just successfully closed.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_writing_and_running_an_lra_participant">Writing and running an LRA participant</h2>
<div class="sectionbody">
<div class="paragraph"><p>We will generate and run a microservice that participates in an LRA using quarkus. A participant should be a JAX-RS resource so we will use the <code>quarkus-maven-plugin</code>, specifying the <code>resteasy-jackson</code> and <code>rest-client</code> extensions (the reason we need <code>rest-client</code> is that the <code>narayana-lra</code> participant support is implemented via a JAX-RS filter which will intercept business requests and needs to invoke the coordinator via JAX-RS calls):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>cd <span style="color: #990000">..</span>
mvn io<span style="color: #990000">.</span>quarkus<span style="color: #990000">:</span>quarkus-maven-plugin<span style="color: #990000">:</span><span style="color: #993399">2.0</span><span style="color: #990000">.</span><span style="color: #993399">1</span><span style="color: #990000">.</span>Final<span style="color: #990000">:</span>create <span style="color: #990000">\</span>
-DprojectGroupId<span style="color: #990000">=</span>org<span style="color: #990000">.</span>acme <span style="color: #990000">\</span>
-DprojectArtifactId<span style="color: #990000">=</span>narayana-lra-quickstart <span style="color: #990000">\</span>
-Dextensions<span style="color: #990000">=</span><span style="color: #FF0000">"resteasy-jackson,rest-client"</span>
cd narayana-lra-quickstart</tt></pre></div></div>
<div class="paragraph"><p>There is an outstanding pull request for a narayana-lra quarkus extension (<code>io.quarkus:quarkus-narayana-lra</code>) which includes the necessary support for LRA. Since that isn’t available yet you need to manually do what the extension will do (which, fortunately, is neither difficult nor complex):</p></div>
<div class="paragraph"><p>Include the following maven dependencies in the generated pom:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt> <span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.eclipse.microprofile.lra<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>microprofile-lra-api<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>1.0<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><dependency></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><groupId></span></span>org.jboss.narayana.rts<span style="font-weight: bold"><span style="color: #0000FF"></groupId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><artifactId></span></span>narayana-lra<span style="font-weight: bold"><span style="color: #0000FF"></artifactId></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"><version></span></span>5.12.0.Final<span style="font-weight: bold"><span style="color: #0000FF"></version></span></span>
<span style="font-weight: bold"><span style="color: #0000FF"></dependency></span></span></tt></pre></div></div>
<div class="paragraph"><p>These two dependencies pull in support for the MicroProfile LRA annotations and the Narayana LRA implementation of the behaviour implied by these annotations.</p></div>
<div class="paragraph"><p>We also need to tell quarkus (via the application.properties config file) to exclude some types from its CDI processing (these types are pulled in by the narayana dependency):</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>echo <span style="color: #FF0000">"quarkus.arc.exclude-types=io.narayana.lra.client.internal.proxy.nonjaxrs.LRAParticipantRegistry,io.narayana.lra.filter.ServerLRAFilter,io.narayana.lra.client.internal.proxy.nonjaxrs.LRAParticipantResource"</span> <span style="color: #990000">>></span> src/main/resources/application<span style="color: #990000">.</span>properties</tt></pre></div></div>
<div class="paragraph"><p>And finally, we just need to update the generated Java JAX-RS resource source code to make use of Long Running Actions (which is the most interesting part for developers):</p></div>
<div class="paragraph"><p>Open the file <code>src/main/java/org/acme/GreetingResource.java</code> in an editor and annotate the <code>hello</code> method with an <code>@LRA</code> annotation.
In addition add two callback methods which will be called when the LRA is closed or cancelled.</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-style: italic"><span style="color: #9A1900">// import annotation definitions</span></span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">;</span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Compensate<span style="color: #990000">;</span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>Complete<span style="color: #990000">;</span>
<span style="font-style: italic"><span style="color: #9A1900">// import the definition of the LRA context header</span></span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> <span style="font-weight: bold"><span style="color: #0000FF">static</span></span> org<span style="color: #990000">.</span>eclipse<span style="color: #990000">.</span>microprofile<span style="color: #990000">.</span>lra<span style="color: #990000">.</span>annotation<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>LRA<span style="color: #990000">.</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">;</span>
<span style="font-style: italic"><span style="color: #9A1900">// import some JAX-RS types</span></span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>PUT<span style="color: #990000">;</span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>core<span style="color: #990000">.</span>Response<span style="color: #990000">;</span>
<span style="font-weight: bold"><span style="color: #000080">import</span></span> javax<span style="color: #990000">.</span>ws<span style="color: #990000">.</span>rs<span style="color: #990000">.</span>HeaderParam<span style="color: #990000">;</span>
<span style="color: #990000">...</span>
<span style="font-style: italic"><span style="color: #9A1900">// annotate the hello method so that it will run in an LRA:</span></span>
@GET
@<span style="font-weight: bold"><span style="color: #000000">Produces</span></span><span style="color: #990000">(</span>MediaType<span style="color: #990000">.</span>TEXT_PLAIN<span style="color: #990000">)</span>
@<span style="font-weight: bold"><span style="color: #000000">LRA</span></span><span style="color: #990000">(</span>LRA<span style="color: #990000">.</span>Type<span style="color: #990000">.</span>REQUIRED<span style="color: #990000">)</span> <span style="font-style: italic"><span style="color: #9A1900">// an LRA will be started before method execution and ended after method execution</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">String</span> <span style="font-weight: bold"><span style="color: #000000">hello</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="font-weight: bold"><span style="color: #0000FF">return</span></span> <span style="color: #FF0000">"Hello RESTEasy"</span><span style="color: #990000">;</span>
<span style="color: #FF0000">}</span>
<span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA closes:</span></span>
@PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
@<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/complete"</span><span style="color: #990000">)</span>
@Complete
<span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">completeWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #FF0000">}</span>
<span style="font-style: italic"><span style="color: #9A1900">// ask to be notified if the LRA cancels:</span></span>
@PUT <span style="font-style: italic"><span style="color: #9A1900">// must be PUT</span></span>
@<span style="font-weight: bold"><span style="color: #000000">Path</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"/compensate"</span><span style="color: #990000">)</span>
@Compensate
<span style="font-weight: bold"><span style="color: #0000FF">public</span></span> <span style="color: #008080">Response</span> <span style="font-weight: bold"><span style="color: #000000">compensateWork</span></span><span style="color: #990000">(</span>@<span style="font-weight: bold"><span style="color: #000000">HeaderParam</span></span><span style="color: #990000">(</span>LRA_HTTP_CONTEXT_HEADER<span style="color: #990000">)</span> <span style="color: #008080">String</span> lraId<span style="color: #990000">)</span> <span style="color: #FF0000">{</span>
<span style="font-weight: bold"><span style="color: #0000FF">return</span></span> Response<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">ok</span></span><span style="color: #990000">().</span><span style="font-weight: bold"><span style="color: #000000">build</span></span><span style="color: #990000">();</span>
<span style="color: #FF0000">}</span></tt></pre></div></div>
<div class="paragraph"><p>Now build and start the application:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>mvn clean package -DskipTests
java -Dquarkus<span style="color: #990000">.</span>http<span style="color: #990000">.</span><span style="color: #009900">port</span><span style="color: #990000">=</span><span style="color: #993399">8081</span> -jar target/quarkus-app/quarkus-run<span style="color: #990000">.</span>jar <span style="color: #990000">&</span></tt></pre></div></div>
<div class="paragraph"><p>Ensure that the application and the coordinator are running on different ports, here I use 8081 for the application with the coordinator listening on port 8080 which is the default (I will show in a later blog how to change the default location of the coordinator).</p></div>
<div class="paragraph"><p>Make a REST request to the hello method:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>curl http<span style="color: #990000">:</span>//localhost<span style="color: #990000">:</span><span style="color: #993399">8081</span>/hello</tt></pre></div></div>
<div class="paragraph"><p>Just before the hello method is invoked an LRA will be started and the participant resource will be enlisted with the LRA. After the method finishes the LRA will be ended automatically (which is the default behaviour of the <code>@LRA</code> annotation). Ending the LRA triggers the termination phase in which the coordinator will invoke the <code>@Complete</code> method (called <code>completeWork</code> in the example) or the <code>@Compensate</code> method (called <code>compensateWork</code> in the example) of each enlisted participant depending on whether the LRA is <code>closing</code> or <code>cancelling</code>. If you want to verify that things are working as expected try updating the resource example to print the value of the HTTP header called <code>Long-Running-Action</code> (see the Java constant <code>LRA_HTTP_CONTEXT_HEADER</code>) which gets injected as a method parameter to each of the annotated methods. Alternatively run the participant in a debugger, for example if you break point inside the hello method and inspect the <code>lraId</code> method parameter and then compare it with what the coordinator knows (<code>curl http://localhost:8080/lra-coordinator</code>) then you should notice that the LRA is in the <code>Active</code> state. Then release the debugger and check back with the coordinator (the LRA will be gone since it should have completed). Note also that the <code>lraId</code> parameter should be the same as the one passed to the <code>@Complete</code> method so setting a break point in that method may also be illuminating.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_recap_of_what_we_8217_ve_said_before_about_compensations">Recap of what we’ve said before about compensations</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_12_2017_a_href_https_jbossts_blogspot_com_search_q_narayana_lra_3a_implementation_of_saga_transactions_narayana_lra_implementation_of_saga_transactions_a">12/2017 <a href="https://jbossts.blogspot.com/search?q=Narayana+LRA%3A+implementation+of+saga+transactions">Narayana LRA: implementation of saga transactions</a></h3>
<div class="paragraph"><p>In this blog Ondra Chaloupka provided an overview of the Saga pattern and then identified those features of LRA that implement the pattern.
His article also provided links to the Narayana code and quickstarts, and in particular introduced a worked example of how to run it in a cloud based environment using Minishift (OpenShift on your laptop).</p></div>
</div>
<div class="sect2">
<h3 id="_12_2017_a_href_https_jbossts_blogspot_com_search_q_saga_implementations_comparison_saga_implementations_comparison_a">12/2017 <a href="https://jbossts.blogspot.com/search?q=Saga+implementations+comparison">Saga implementations comparison</a></h3>
<div class="paragraph"><p>Another interesting article contributed by Ondra where he takes a different approach to explaining the concepts and mechanics of LRA’s. In this essay he compares and contrasts the Narayana LRA implementation with two popular Saga implementations: Axon framework and Eventuate.io. This approach is particularly useful for users already familiar with these other frameworks to get a rapid understanding of what LRA is offering.</p></div>
</div>
<div class="sect2">
<h3 id="_11_2017_a_href_https_jbossts_blogspot_com_search_q_a_comparison_of_long_running_actions_with_a_recent_wso_paper_a_comparison_of_long_running_actions_with_a_recent_wso_paper_a">11/2017 <a href="https://jbossts.blogspot.com/search?q=A+comparison+of+Long+Running+Actions+with+a+recent+WSO+paper">A comparison of Long Running Actions with a recent WSO paper</a></h3>
<div class="paragraph"><p>Tom Jenkinson proves "a high-level comparison of the approach taken by the LRA framework with a paper released to the 2017 IEEE 24th International Conference on Web Services - “WSO: Developer-Oriented Transactional Orchestration of Web-Services”." describing the various concepts introduced in both approaches: ordering compensations, idempotency, structure, ease of use, locking and orchestration and nesting of activities.</p></div>
<div class="paragraph"><p>Tom describes LRA thus: "This specification is tailored to addressing needs of applications which are running in highly concurrent environments and have the need to ensure updates to multiple resources have atomic outcomes, but where locking of the resource manager has an unacceptable impact on the overall throughput of the system. LRA has been developed using a cloud first philosophy and achieves its goal by providing an extended transaction model based on Sagas. It provides a set of APIs and components designed to work well in typical microservice architectures."</p></div>
</div>
<div class="sect2">
<h3 id="_06_2017_a_href_https_jbossts_blogspot_com_search_q_sagas_and_how_they_differ_from_two_phase_commit_sagas_and_how_they_differ_from_two_phase_commit_a">06/2017 <a href="https://jbossts.blogspot.com/search?q=Sagas+and+how+they+differ+from+two-phase+commit">Sagas and how they differ from two-phase commit</a></h3>
<div class="paragraph"><p>Yet another article provided by Ondra, a busy year for him. Each of Ondra’s 2017 articles, though focused on communicating what LRA is and when, where and why it can be useful, do an excellent job at covering different facets of the compensation based approach to achieving distributed consistency. Ondra provides an extensive overview of the various concepts involved in these two transaction models [sagas and LRA’s].</p></div>
<div class="paragraph"><p>Of particular interest is the extensive set of references provided at the end of the blog.</p></div>
</div>
<div class="sect2">
<h3 id="_10_2016_a_href_https_jbossts_blogspot_com_search_q_achieving_consistency_in_a_microservices_architecture_achieving_consistency_in_a_microservices_architecture_a">10/2016 <a href="https://jbossts.blogspot.com/search?q=Achieving+Consistency+in+a+Microservices+Architecture">Achieving Consistency in a Microservices Architecture</a></h3>
<div class="paragraph"><p>This article provides an overview of the problem domain that LRA addresses and draws attention to some of the difficulties that naive approaches run into when attempting their resolution.
Although the article, written in 2016, predates the Narayana LRA implementation it does outline the basic LRA protocol.</p></div>
</div>
<div class="sect2">
<h3 id="_07_2013_compensating_transactions_when_acid_is_too_much">07/2013 Compensating Transactions: When ACID is too much</h3>
<div class="paragraph"><p>An epic four part series contributed by Paul Robinson covering many aspects of the compensation based approach to transactions:</p></div>
<div class="paragraph"><p><a href="https://jbossts.blogspot.com/2013/05/compensating-transactions-when-acid-is.html">Part 1: Introduction</a></p></div>
<div class="paragraph"><p><a href="https://jbossts.blogspot.com/2013/05/compensating-transactions-when-acid-is_29.html">Part 2: Non-transactional Work</a>. This part will cover situations where you need to coordinate multiple non-transactional resources, such as sending an email or invoking a third party service.</p></div>
<div class="paragraph"><p><a href="http://jbossts.blogspot.co.uk/2013/06/compensating-transactions-when-acid-is_26.html">Part 3: Cross-domain Distributed Transactions</a>: This part covers a scenario where the transaction is distributed, and potentially crosses multiple business domains.</p></div>
<div class="paragraph"><p><a href="https://jbossts.blogspot.com/2013/07/compensating-transactions-when-acid-is.html">Part 4: Long-lived Transactions</a>. This part covers transactions that span long periods of time and shows how it’s possible to continue the transaction even if some work fails.</p></div>
</div>
<div class="sect2">
<h3 id="_05_2015_a_href_https_jbossts_blogspot_com_2015_05_xa_and_microservices_html_xa_and_microservices_a_05_2014_a_href_http_jbossts_blogspot_com_2014_05_transactions_and_microservices_html_transactions_and_microservices_a_and_04_2015_a_href_https_jbossts_blogspot_com_2015_04_microservices_and_transactions_update_html_microservices_and_transactions_an_update_a">05/2015 <a href="https://jbossts.blogspot.com/2015/05/xa-and-microservices.html">XA and microservices</a>, 05/2014 <a href="http://jbossts.blogspot.com/2014/05/transactions-and-microservices.html">Transactions and Microservices</a> and 04/2015 <a href="https://jbossts.blogspot.com/2015/04/microservices-and-transactions-update.html">Microservices and transactions - an update</a></h3>
<div class="paragraph"><p>Three posts in which Mark allays a number of fears, concerns and fallacies that developers may have with combining transactions with microservices.</p></div>
</div>
<div class="sect2">
<h3 id="_03_2011_a_href_https_jbossts_blogspot_com_2011_03_slightly_alkaline_transactions_if_you_html_slightly_alkaline_transactions_if_you_please_8230_a">03/2011 <a href="https://jbossts.blogspot.com/2011/03/slightly-alkaline-transactions-if-you.html">Slightly alkaline transactions if you please …</a></h3>
<div class="paragraph"><p>Mark introduces his short post with:
"Given that the traditional ACID transaction model is not appropriate for long running/loosely coupled interactions, let’s pose the question, “what type of model or protocol is appropriate?”",
and then he goes on to answer the question he poses. Along the way we find definitions and links to papers that define various extensions to the traditional model giving us the "lay of land", so to speak, to enable us to navigate our way to an understanding of alternate models.</p></div>
</div>
<div class="sect2">
<h3 id="_03_2011_a_href_https_jbossts_blogspot_com_2011_03_when_acid_is_too_strong_html_when_acid_is_too_strong_a">03/2011 <a href="https://jbossts.blogspot.com/2011/03/when-acid-is-too-strong.html">When ACID is too strong</a></h3>
<div class="paragraph"><p>Another short post in which Mark presents the motivation for long-running activities.</p></div>
</div>
<div class="sect2">
<h3 id="_03_2011_a_href_https_jbossts_blogspot_com_2011_03_rest_cloud_and_transactions_html_rest_cloud_and_transactions_a">03/2011 <a href="https://jbossts.blogspot.com/2011/03/rest-cloud-and-transactions.html">REST, Cloud and transactions</a></h3>
<div class="paragraph"><p>Mark motivates the case for REST based transaction protocols as a <a href="http://docs.oasis-open.org/ws-tx/wsba/2006/06">complement to WS-Transactions</a>. LRA is such a REST based protocol and his post provides important background material on why LRA exists alongside WS-BA.</p></div>
</div>
<div class="sect2">
<h3 id="_10_2011_a_href_https_jbossts_blogspot_com_search_q_nested_transactions_101_nested_transactions_101_a">10/2011 <a href="https://jbossts.blogspot.com/search?q=nested+transactions+101">nested transactions 101</a></h3>
<div class="paragraph"><p>Some useful background information on nested transactions (partially motivates nested LRA’s)</p></div>
</div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated
2021-07-14 11:05:48 BST
</div>
</div>Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-22400357824421399922021-06-09T17:32:00.000+01:002021-06-09T17:32:21.598+01:00Narayana 5.12.0.Final releasedThis week we released Narayana 5.12.0.Final. You can download it from our website at https://narayana.io/downloads/index.html
This release includes a mix of enhancements (including support for CDI 2.0) and bug fixes, full details can be found in the <a href="https://issues.redhat.com/secure/ReleaseNote.jspa?projectId=12310200&version=12358585">release notes.</a>Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-7437342804075317122021-03-22T14:50:00.002+00:002021-03-22T14:50:27.861+00:00Narayana 5.11.0.Final released<p>The team are pleased to announce our latest release of Narayana - the premier open source transaction manager.</p><p>The release is available for <a href="https://narayana.io/downloads/index.html">download from our website</a>.</p><p>The release includes a mix of new features, <a href="https://narayana.io//docs/project/index.html#d0e15502">LRA</a> and <a href="https://issues.redhat.com/browse/JBTM-3276">slot store</a>, plus a number of other smaller enhancements together with bug fixes. A full list of what we fixed is available in the <a href="https://issues.redhat.com/secure/ReleaseNote.jspa?projectId=12310200&version=12354588">release notes</a>.</p><p>As always we generate comparative TPS figures for each release and this new release <a href="https://github.com/jbosstm/artifacts/blob/master/jobs/tm-comparison/benchmark.png">performs</a> favourably against other open source transaction managers.</p>Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-60294500245341626122019-12-04T15:17:00.000+00:002019-12-04T15:17:32.970+00:00Narayana 5.10.1.Final releasedThe team are pleased to announce our latest release of Narayana - the premier open source transaction manager.<br />
<br />
The release is available for <a href="http://narayana.io/downloads/index.html">download</a> from our website.<br />
It is a bug fix release and a list of what we fixed is available in the <a href="https://issues.jboss.org/secure/ReleaseNote.jspa?projectId=12310200&version=12343104">release notes</a>.<br />
<br />
We always generate comparative TPS figures for each release and this new release <a href="https://github.com/jbosstm/artifacts/blob/master/jobs/tm-comparison/benchmark.png">performs</a> favourably against other open source transaction managers.Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-54322123841179589742019-11-08T10:24:00.002+00:002019-11-08T10:24:48.084+00:00Narayana 5.10.0.Final releasedThe team are pleased to announce our latest release of Narayana - the premier open source transaction manager.<br />
<br />
The release is available for <a href="http://narayana.io/downloads/index.html">download</a> from our website.<br />
It is a bug fix release and a list of what we fixed is available in the <a href="https://issues.jboss.org/secure/ReleaseNote.jspa?projectId=12310200&version=12342779">release notes</a>.<br />
<br />
<br />Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-27562867586969409862019-10-07T10:57:00.001+01:002019-10-07T11:30:22.126+01:00Software Transactional Memory with QuarkusWe have recently contributed a <a href="https://github.com/quarkusio/quarkus/tree/master/extensions/narayana-stm">quarkus extension called quarkus-narayana-stm</a> which simplifies the use of STM in your microservices.<br />
<br />
It will be available in the 0.24.0 quarkus release. If you would like to experiment with it before this release then you can either take one of the <a href="https://oss.sonatype.org/content/repositories/snapshots/io/quarkus/quarkus-narayana-stm/">nightly builds</a> or you can build it locally by git cloning the <a href="https://github.com/quarkusio/quarkus">quarkus repo</a> and then run the build. This will add the io.quarkus:quarkus-narayana-stm:999-SNAPSHOT maven dependency to your local maven repository and you may then get started by <a href="https://github.com/quarkusio/quarkus/blob/master/docs/src/main/asciidoc/stm-guide.adoc#using-software-transactional-memory-in-quarkus">following the guide</a>. There is also a <a href="https://github.com/quarkusio/quarkus-quickstarts/tree/development/using-software-transactional-memory">quickstart</a> that provides a worked example of how to use it in your microservices. The example shows how to manage concurrent accesses to a single counter. More sophisticated usage patterns are the norm but this simple example does give a flavour of how easy it is to manage concurrency with the Narayana STM implementation.<br />
<br />Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com2tag:blogger.com,1999:blog-8686578724458335326.post-89311955754724885912019-09-18T18:56:00.002+01:002019-10-30T11:53:06.272+00:00Heuristic exceptions<p>
A transaction is finished either with commit or rollback.
But have you considered that the third transaction outcome is <i><<unspecified>></i>?
This third type of outcome may occur when the participant does not follow the coordinator's orders and makes a decision on the contrary. Then the outcome of the whole
transaction could be inconsistent. Some participants could follow the coordinator
guidelines to commit while the disobedient participant rolls-back. In such a case, the coordinator cannot report back to the application that "the work was successfully finished".
From the perspective of the outside observer, the consistency is damaged.
The coordinator itself cannot do much more. It followed the rules
of the protocol but the participants disobeyed. Such transaction can only
be marked with <i><<unspecified>></i> result — which is known as heuristic outcome.<br/>
The resolution of that outcome requires a third-party intervention.
Saying differently somebody has to go and verify the state of data and
make corrections.
</p>
<h2>XA specification</h2>
<p>
In scope of this article we talk about the <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">two phase commit protocol</a> and
how the <a href="http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf">XA specification</a> uses it.<br/>
XA specification takes the two-phase commit, the abstractly defined consensus protocol,
and carries it down to the ground of implementation. It defines rules for communication amongst parties,
prescribes state model and assesses outcomes, exceptions etc.<br/>
Where the 2PC talks about coordinator and participants the XA specification
define a model where the coordinator is represented by a transaction manager (TM), the participant is modelled as the resource manager (RM)
and the employer of them is an application program which talks to both of them.<br/>
The transaction manager drives a global transaction which enlists resource managers as participants responsible for part of work. For the work managed by RM is used term transaction branch.
The resource manager is represented normally by a Java code that implements the JTA API
while it uses some internal mechanism to call the underlying data resource.
The resource manager could be represented by a JDBC driver and then underlying resource
could be the PostgreSQL database running in some distinct datacenter.
</p>
<h2>JTA Specification</h2>
<p>
The <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr907/index3.html">Java Transaction API</a>
is a projection of XA specification to the language of Java. In general, it's a high-level API that strives to provide
a comprehensible tool for handling transactional code based on the XA specification.
</p>
<h3>Several purposes of JTA</h3>
<p>
The JTA is meant to be used first by an application developer. In terms of XA specification, it would be the application program.
Here we have the <a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/UserTransaction.java">UserTransaction</a> interface.
It gives the chance to <code>begin</code> and <code>commit</code> the transaction.
In terms of XA specification, it's a representation of the global transaction.
In a newer version (from version 1.2) JTA defines the annotations like
<a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/Transactional.java">Transactional</a>
That gives the user chance to control the application scope declaratively.
As you can notice neither with the <code>UserTransaction</code> nor with he <code>@Transactional</code> annotation
you can't do much more than to define where the transaction begins and where it ends.
How to put a participant into the transaction? That limited capability is because developer is anticipated
running the application in a managed environment. It could be for example <a href="https://wildfly.org">Java EE application server</a>
or <a href="https://quarkus.io">a different container</a>.
</p>
<p>
The container is a second consumer of the JTA API. JTA gives the entry point to the world of transaction management.
The container uses the interface
<a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/TransactionManager.java#L23">TransactionManager</a>
— which provides ability of managing transaction scope but also gives access to
the <a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/Transaction.java#L24">Transaction</a>
object itself. <code>Transaction</code> is used to enlist the resource (the participant) to the global transaction.
As the resource for enlistment is used the <code>XAResource</code> interface in JTA.
The <code>XAResource</code> is managed by the transaction manager and is operated by the resource manager.
Then container may arrange
<a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/Synchronization.java">Synchronization</a>s
are callbacks called at the start and the end of the 2PC processing
(used e.g. by <a href="https://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html">JPA</a>).
</p>
<p>
The third perspective where JTA participates in is communication with resource managers.
The API defines the class <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAResource.html">XAResource</a>
(represents a participant resource to be enlisted to the global transaction),
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAException.html">XAException</a>
(represents an error state defined in the XA specification) and
<a href="">Xid</a>. The Xid
represents an identifer which is unique for each transaction branch and consists of two parts
— first an unique identifier of the global transaction and second an unique identifier of the resource manager.
If you want to see how the transaction manager uses these classes to communicate
with the resource manager take a look
<a href="https://docs.microsoft.com/en-us/sql/connect/jdbc/understanding-xa-transactions?redirectedfrom=MSDN&view=sql-server-2017#example">at the example from documentation of SQL Server</a>.
</p>
<p><i>Note:</i>If you study the JTA API by looking into the javadoc and strolling
<a href="https://docs.oracle.com/javase/10/docs/api/javax/transaction/package-summary.html">the package summary</a> then
you can wonder about some other classes which were not mentioned here.
Part of the <code>javax.transaction</code> package
are interfaces used exclusively by JTS (transaction services running with ORB).
That's mitigated by the fact the Java SE 11 removed support of ORB
and those classes were removed from JDK as well.<br/>
Plus the JTA classses are now (from Java SE 11) split over Java SE and Java EE bundles
as the package <code>javax.transaction.xa</code>
is solely part of the Java SE while <code>javax.transaction</code> belongs
to the <a href="">Jakarta EE API</a>.
</p>
<h2>Type of failures</h2>
<p>
Now when we have talked the model let's see the failure states.
First, it's needed to realize that a failure in the application does not mean failure from
the protocol perspective. If there is trouble in the application code
or a network is transiently not available such occurrences can lead
to rollback. It's a failure from the perspective of the application but
for the transaction manager the rollback is just another valid state to shift to.<br/>
Even if the whole transaction manager crashes (e.g. the underlying JVM is killed)
the system still should maintain data consistency and the transaction is recovered
when the transaction manager (or rather
<a href="https://jbossts.blogspot.com/2018/01/narayana-periodic-recovery-of-xa.html">recovery manager</a>)
comes back to life.
</p>
<p>
What's the trouble for the protocol is an unexpected behaviour of the resource manager (or the backed resource).
We can track basically two incident types. A heuristic outcome where the resource deliberately decides
to process some action (which is different from transaction manager decision).
Or a heuristic outcome caused by a bug in the code (either of the transaction manager or the resource manager).
</p>
<p>
Let's discuss some examples for these types.<br/>
The deliberate decision could be a situation where the transaction manager
calls the <code>prepare</code> on the database. The database confirms the <code>prepare</code> — it promises
to finish the transaction branch with commit. But unfortunately the transaction
manager crashes and nobody comes to restart it for a long time. The database decides that it's
pretty long time to hold resources and delaying other transactions to proceed.
Thus it decides to commit the work. The processing in the database may continue from that time.
But later the transaction manager is restarted and it tries to commit all other branches
belonging to the global transaction (let's say e.g. a JMS broker).
That resource responds with an error and the transaction manager
decides to rollback the whole global transaction. Now it accesses the database with the request for the rollback.
But the database already committed its branch — the heuristic outcome just occurred.
</p>
<p>
An example for the bug in the code could be the PostgreSQL database driver.
The driver was <a href="https://github.com/pgjdbc/pgjdbc/pull/782">returning a wrong error code</a>
in case of intermittent connection failure. The XA specification defines that
in such case the <code>XAException</code> should be thrown and it has to carry one of the following error codes — either the
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAException.html#XAER_RMFAIL">XAException.XAER_RMFAIL</a>
or the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAException.html#XA_RETRY">XAException.XA_RETRY</a>.
But the JDBC driver was returning <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAException.html#XAER_RMERR">XAException.XAER_RMERR</a>.
Such error code means that an irrecoverable error occurred. It makes
the transaction manager think there is no way of automatic recovery
and it switches the state of such transaction to heuristic immediately.
</p>
<h2>Heuristic exceptions</h2>
<p>
As the last part of this article we take a look on the heuristic outcomes of the transaction.
The heuristics is represented with an exception being thrown. The exception reports the
reason of the failure. It does so with error code or with type of class.
</p>
<p>
There are two main types of exception classes. First type is the <code>XAException</code>.
This one is part of the communication contract between the transaction manager and the resource manager.
It should not happen for the application code to obtain this type of exception. But for sure
you can observe the <code>XAException</code> in the container log. It shows
that there happened an error during transaction processing.
</p>
<p>
The second type is represented with multiple classes named
<a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/HeuristicCommitException.java">Heuristic*Exception</a>.
These are exceptions that application code works with.
They are thrown from the <code>UserTransaction</code> methods and they are
<a href="https://howtodoinjava.com/java/exception-handling/checked-vs-unchecked-exceptions-in-java/">checked</a>.
</p>
<h3>Heuristic outcome with XAResource</h3>
<p>
The <code>XAException</code> reports reason of failure with the use of error codes.
XA specification defines the meaning. It depends on the context in which it's used.
For example the code <code>XAException.XA_RETRY</code> could be used for reporting error
from <code>commit</code> with meaning to retry the commit action.
But on the other hand it's not permitted to be used as an error code for
the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.transaction.xa/javax/transaction/xa/XAResource.html#commit(javax.transaction.xa.Xid,boolean)">one-phase commit</a>.
</p>
<p>
Then where are those heuristic states? Let's check what could happen when the transaction manager
calls the <code>XAResource</code> calls of <code>prepare</code>, <code>commit</code> and <code>rollback</code>.<br/>
If the <code>prepare</code> is called then there is not many chances that heuristic occurs.
At that time no promise from the resource is placed and the work can be easily
roll-back or the worse timed-out. The only occurrence that can bring the system to the heuristic
state is if the resource manager returns undefined code for this phase.
But that is cause the most probably only by a bug in the implementation.
Consult the XA specification which are those.<br/>
The more interesting are the <code>commit</code> and <code>rollback</code> calls.
The <code>commit</code> and <code>rollback</code> are (or could be) called after the <code>prepare</code>.
Heuristic exception means that the resource promised to commit
(he acknowledge the prepare call) but it does not wait for transaction manager
to command it for the next action and it finished the transaction branch on its own.
The error codes are those with prefix <code>XA_HEUR*</code>.
The decision on its own does not mean an error for the protocol in all cases.
</p>
<p>
Let's talk about <code>rollback</code> now. The global transaction was successfully
prepared but the transaction manager decided at the end to roll-back it.
It calls the <code>rollback</code> to the <code>XAResource</code>.
The error <code>XAException.XA_HEURRB</code> announces that the resource manager
decided to roll-back the transaction branch prior it was asked for it by the transaction manager.
But as the transaction manager decided to go for the roll-back too
the heuristic outcome followed the decision.<br/>
The <code>XAException.XA_HEURCOM</code> means that all work
represented by the transaction branch was committed (at time the <code>rollback</code> is executed on the <code>XAResource</code>).
That's bad from the data consistency
as some other transaction branches could be already rolled-back.<br/>
To explain the meaning of the <code>XAException.XA_HEURMIX</code> it's needed to mention that the transaction
branch could consist of several "local transactions". For example, PostgreSQL JDBC
driver starts a database transaction to insert data to the database. Later
(still in the scope of the same global transaction) it decides to update the data. It starts
another database transaction. The transaction manager is clever enough
to join those two database transactions which belong to the same database resource (controlled by the same resource manager)
under the one transaction branch. It's good
as it could reduce the communication overhead.
So the <code>XA_HEURMIX</code> says that part of workload involved in the transaction branch
was committed and the other part was rolled-back.<br/>
The <code>XAException.XA_HEURHAZ</code> says that the resource manager made a decision on its own
but it's not capable to say what was the result of such an independent decision.
</p>
<p>
The most interesting part is the <code>commit</code> call. First it uses the <code>XA_HEUR*</code>
exceptions in the same meaning as the <code>rollback</code> call
and all what is said in the previous paragraph pays for the <code>commit</code> too.
But up to that there are three new error codes. They do not contain word <i>HEUR</i>
but in result they mean it.
Those are <code>XAER_RMERR</code>
which announces that an unspecified error happened during the currently executing <code>commit</code>
call. But instead of committing the resource manager had just rolled-back the transaction branch.
That means we are in the same state as with the <code>XA_HEURRB</code>
The <code>XAER_NOTA</code> says that resource manager does not know
anything about this transaction branch. That means the resource manager lost the notion
about it and it either commits it or rolled-back it or it may do an arbitrary one in the future.
That means we are in the same state as with the <code>XA_HEURHAZ</code>.
The last one is the <code>XAER_PROTO</code> which says that the <code>commit</code>
was called in a wrong context — for example it was called
without the <code>prepare</code> being invoked before. This seems being similar
to <code>XAER_NOTA</code> and thus have the same impact as the <code>XA_HEURRB</code>.
</p>
<h3>Heuristic outcome with the "application exceptions"</h3>
<p>
For the "application exceptions" it could be considered easier. The heuristic exceptions
can be thrown only from the <code>commit</code> call
(<a href="https://github.com/eclipse-ee4j/jta-api/blob/1.3.3/api/src/main/java/javax/transaction/UserTransaction.java#L43">see UserTransaction javadoc</a>).
The <code>UserTransaction</code> gives chance to finish the transaction with <code>commit</code> or <code>roll-back</code>.
</p>
<p>
The roll-back means that transaction branches should be aborted and all work discarded.
When <code>UserTransaction.rollback()</code> is called the resource manager had not promised succesful outcome yet.
The time the <code>rollback</code> is called is time when all transaction processing data is available only in memory.
Thus resource manager has no chance to decide differently from transaction manager. If there is some trouble then other types
of exceptions are thrown — like <code>IllegalStateException</code> or <code>SystemException</code>
(<a href="https://github.com/eclipse-ee4j/jta-api/blob/1.3.3/api/src/main/java/javax/transaction/UserTransaction.java">see the UserTransaction javadoc</a>).
</p>
<p>
It's different with the <code>UserTransaction.commit</code>. This call means that two-phase commit protocol
is to be started and <code>XAResource.prepare/commit/rollback</code> calls are involved.
The JTA uses the checked exceptions to inform the application to handle the trouble.
The application checked exceptions are <code>RollbackException</code>,<code>HeuristicMixedException</code>,<code>HeuristicRollbackException</code>.
<ul>
<li>
The <code>RollbackException</code> is not a heuristic exception (at least by name) but still.
That exception informs that even the code asked for commit all work (in all transaction branches) was undone by the rollback.
</li>
<li>
The <code>HeuristicMixedException</code> means that some transaction branches were committed
and others were rolled-back. This is exception thrown for example if during
the commit phase of 2PC. One of the <code>XAResource.commit</code> calls
returns <code>XAException.XA_HEURRB</code> (aka it was rolled-back)
while the others were succesfully committed.<br/>
</li>
<li>
The <code>HeuristicRollbackException</code> has the same final outcome from the global transaction perspective as the <code>RollbackException</code>.
It only emphasizes that the fact that the roll-back was deliberately chosen by all the resources prior to the <code>commit</code>
was executed by the transaction manager. In comparison, the <code>RollbackException</code> means
that the transaction manager was just trying to commit
all resources but during the process of committing trouble occurred and all the work was rolled-back (all resources rolled-back). To be perfectly honest I'm not sure I can't see a real difference between these two.
</li>
</ul>
</p>
<p>
As we've just talked about all exceptions defined at the
<a href="https://github.com/eclipse-ee4j/jta-api/blob/1.3.3/api/src/main/java/javax/transaction/UserTransaction.java#L43">UserTransaction.commit</a> definition so we are done, right?</br>
Oh wait, we are not!
</p>
<p>
There is one more exception defined in the <code>javax.transaction</code> package.
It's the <a href="https://github.com/eclipse-ee4j/jta-api/blob/master/src/main/java/javax/transaction/HeuristicCommitException.java">HeuristicCommitException</a>.
The <code>HeuristicCommitException</code> is not defined at the <code>UserTransaction.commit</code>
as even all resources would idependently decide to commit the global transaction
result is still just committed. Which is intended as <code>UserTransaction.commit</code> is called.
Then what is the purpose of it then?<br/>
We need to <a href="https://github.com/jbosstm/narayana/blob/5.9.8.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinateTransaction.java#L62">look into the implementation</a>.
It's used at calls of commit and rollback at a subordinate transaction. The subordinate transaction
is a transaction which is driven by a parent transaction. The parent transaction (named as top-level as well)
manages the subordinate and decides the overall outcome.<br/>
When the subordinate transaction is commanded it reports the outcome back to the top-level one.
It's a similar relation as the <code>XAResource</code> has to the global transaction.
Because the subordinate transaction
needs to report heuristic decisions back from the <code>commit</code> and <code>rollback</code> calls
the <code>HeuristicCommitException</code> serves for cases when subordinate transaction
decided to commit prior the top-level transaction commanded for a final action.
</p>
<p><i>NOTE:</i> Don't interchange the subordinate transaction for the nested transaction.
If the nested transaction is aborted the upper transaction can continue
in processing and it can finish with commit at the end (but if the top-level transaction rolls-back
the nested transaction has to roll-back as well).<br/>
The subordinate transaction is a composite part of the top-level transaction. If the subordinate
transaction aborts the top-level one aborts as well.
</p>
<h2>Summary</h2>
<p>
That's all. Hopefully, you understand a bit more on the meaning of the heuristic outcomes for the XA and JTA specifications.
And for sure you won't be writing code like
<pre><code class="java">try {
UserTransaction.begin();
...
UserTransaction.commit();
} catch (Throwable t) {
// some strange error happened so we print it to the log
t.printStackTrace();
}
</code></pre>
</p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-19160780858559825092019-06-26T18:16:00.000+01:002019-06-28T14:36:38.562+01:00Expiry scanners and object store in Narayana<h3>
What are the expiry scanners?</h3>
The expiry scanner serves for garbage collection
of <i>aged</i> transaction records in Narayana.
<br />
Before elaborating on that statement let's first find out
why is such functionality needed.
<br />
<br />
<h3>
Narayana object store and transaction records</h3>
Narayana creates persistent records when process transactions. These records
are saved to the transaction log called Narayana object store.
The records are utilized during transaction recovery when a failure of a transaction happens. Usual reasons for the transaction failure is a crash of the JVM or a network connection issue
or an internal error on the remote participant.
The records are created during the processing of transactions.
Then they are removed immediately after the transaction successfully finishes
(regardless of the transaction outcome – commit or rollback).
That implies that the Narayana log contains only the records
of the currently active transactions and the failed ones.
The records on active transactions are expected to be removed when the transaction finishes.
The records on failed transactions are stored until the time
they are recovered – finished by periodic recovery –
or by the time they are resolved by human intervention.
<br />
...or by the time they are garbage collected by the expiry scanner.
<br />
<br />
Narayana stores transaction record in a hierarchical structure.
The hierarchy location depends on the <i>type</i> of record.
The object store could be stored on the hard drive – either as a directory structure,
or in the journal store (the implementation which is used is created by
<a href="https://activemq.apache.org/components/artemis/">ActiveMQ Artemis project</a>),
or it can be placed to the database via JDBC connection.
<br />
<i><br /></i>
<i><b>NOTE:</b></i> Narayana object store saves data about transaction processing,
but the same storage is used to persist other runtime data
which is expected to survive the crash of the JVM.
<br />
<br />
<h4>
Object store records for JTA and JTS</h4>
Transaction processing records are stored differently independence
whether <a href="https://docs.jboss.org/jbosstm/5.0.0.M1/guides/narayana-jts-development_guide/ch08.html">JTA or JTS mode</a> is used.
The JTA runs the transactions inside the same JVM. While JTS is designed to support distributed transactions.
When JTS is used, the components of the transaction manager are not coupled inside the same JVM.
The components communicate with each other via messages, regardless the components run within the same JVM
or as different processes or on different nodes.
JTS mode saves more transaction processing data to object store than the JTA alternative.
<br />
<br />
For standard transaction processing the JTA starts with the enlisting participant
under <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">the global transaction</a>.
Then two-phase commit starts and prepare is called at each participant.
When the prepare 2PC phase ends, the record informing about the success of the phase is stored under the object store.
After this point, the transaction is predetermined to commit
(until that point the rollback would be processed in case of the failure,
see <a href="http://narayana.io/docs/project/index.html#_transaction_model">presumed rollback</a>).
The 2PC commit phase is processed by calling commit on each participant.
After this phase ends the record is deleted from the object store.
<br />
The <i>prepare</i> "tombstone record" informs about the success of the phase but
contains information on successfully prepared participants which were part of the transaction.<br />
<br />
This is how the transaction object storage looks like after the prepare was successfully processed.
The type which represents the JTA tombstone record is
<code>StateManager/BasicAction/TwoPhaseCoordinator/AtomiAction</code>.<br />
<pre><code class="java">data/tx-object-store/
ShadowNoFileLockStore
└── defaultStore
├── EISNAME
│ ├── 0_ffff0a000007_6d753eda_5d0f2fd1_34
│ └── 0_ffff0a000007_6d753eda_5d0f2fd1_3a
└── StateManager
└── BasicAction
└── TwoPhaseCoordinator
└── AtomicAction
└── 0_ffff0a000007_6d753eda_5d0f2fd1_29</code></pre>
In the case of the JTS, the processing runs mostly the same way. But one difference is
that the JTS saves more setup data (created once during initialization of transaction manager,
see <code>FactoryContact</code>, <code>RecoveryCoordinator</code>).
Then the second difference to JTA is that <strike>the JTS stores the information about each prepared participant separately</strike> for JTS the participants are separate entities and each of them handles the persistence on his own. Because of that, a "<i>prepare record</i>" is created for each participant separately (see Mark's clarification below in comments). When <code>XAResource.prepare</code> is called there is created a record type
<code>CosTransactions/XAResourceRecord</code>. When the <code>XAResource.commit</code>
is called then the record is deleted. After the <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">2PC prepare</a>
is successfully finished the record <code>StateManager/BasicAction/TwoPhaseCoordinator/ArjunaTransactionImple</code>
is created and is removed when the 2PC commit phase is finished. The record <code>ArjunaTransactionImple</code>
is the <i>prepare</i> "tombstone record" for JTS.
<br />
Take a look at how the object store with two participants and finished
2PC prepare phase looks like<br />
<pre><code class="java">data/tx-object-store/
ShadowNoFileLockStore
└── defaultStore
├── CosTransactions
│ └── XAResourceRecord
│ ├── 0_ffff0a000007_-55aeb984_5d0f33c3_4b
│ └── 0_ffff0a000007_-55aeb984_5d0f33c3_50
├── Recovery
│ └── FactoryContact
│ └── 0_ffff0a000007_-55aeb984_5d0f33c3_15
├── RecoveryCoordinator
│ └── 0_ffff52e38d0c_c91_4140398c_0
└── StateManager
└── BasicAction
└── TwoPhaseCoordinator
└── ArjunaTransactionImple
└── 0_ffff0a000007_-55aeb984_5d0f33c3_41</code></pre>
<h4>
</h4>
<h4>
Now, what about the failures? </h4>
When the JVM crashes, network error or another transaction error happens the transaction manager stops to process the current transaction. Depending on the type of failure
it either abandons the state and passes responsibility to finish the transaction to the periodic recovery manager.
That's the case e.g. for the "clean" failures – the JVM crash or the network crash.
The periodic recovery starts processing when the system is restarted and/or
it periodically retries to connect to the participants to finish the transaction.
<br />
Continuing with the object store example above.
JVM crashes and further restarts make that periodic recovery to observe the
2PC prepare was finished – there is the <code>AtomicAction/ArjunaTransactionImple</code> record in the object store.
The recovery manager lists the participants (represented with <code>XAResource</code>s)
which were part of the transaction and it tries to commit them.
<br />
<br />
<h4>
ARJUNA016037: Could not find new XAResource to use for recovering non-serializable XAResource</h4>
Let me make a quick side note to one interesting point in the processing.
Interesting at least from the Narayana perspective.
<br />
If you are using Narayana transaction manager for some time you are
well familiar with the log error message:<br />
<br />
<code>
[com.arjuna.ats.jta] (Periodic Recovery) ARJUNA016037: Could not find new XAResource
to use for recovering non-serializable XAResource XAResourceRecord
</code><br />
<br />
This warning means: <i>There was a successful prepared transaction as we can
observe the record in the object store.
But periodic recovery manager is not capable to find out what is the counterparty
participant – e.g. what database or JMS broker the record belongs to.</i><br />
This situation happens when the failure (JVM crash) happens in a specific time.
That's time just after <code>XAResource.commit</code> is called. It makes the participant
(the remote side - e.g. the database) to remove its knowledge about the transaction from its resource local storage.
But at that particular point in time, the transaction record was not yet removed from the Narayana object store.
<br />
The JVM crash happened so after the application restarts the periodic recovery can observe a record in the object store.
It tries to match such record to the information obtained from
the participant's resource local storage (uses <code>XAResource.recover</code> call).<br />
<br />
As the participant's resource local storage was cleaned there is no information obtained. Now the periodic recovery does see any directly matching information to its record in the object store.
<br />
From that said, we can see the periodic recovery complains that there is a participant
record which does not contain "connection data" as it's non-serializable.
And there is no matching record at the participant's resource local storage.
<br />
<br />
<i><b>NOTE:</b></i>
One possibility to get rid of the warning in the log would be to serialize all the information
about the participant (serializing the <code>XAResource</code>).
Such serialized participants provide an easy way for the periodic recovery manager
to directly call methods on the un-serialized instance (<code>XAResource.recover</code>).
But it would mean to serialize e.g. the
<a href="https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html#getConnection--">JDBC connection</a>
which is hardly possible.<br />
<br />
The description above explains the JTA behaviour. In the case of the JTS,
if the transaction manager found a record in the object store
which does not match any participant's resource local storage info
then the object store record is considered as assumed completed.
Such consideration means changing the type of record in the object store.
Changing the type means moving the record to a different place in the hierarchical
structure of the object store.
When the record is moved to an unknown place for the periodic recovery
it stops to consider it as a problematic one and it stops to print out warnings to the application log.
The record is then saved under <code>ArjunaTransactionImple/AssumedCompleteServerTransaction</code>
in the hierarchical structure.
<br />
This conversion of the in-doubt record to the assumed completed one happens by default
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTS/jts/classes/com/arjuna/ats/jts/common/JTSEnvironmentBean.java#L56">after 3 cycles of recovery</a>.
Changing the number of cycles could be done by providing system property <code>-DJTSEnvironmentBean.commitedTransactionRetryLimit=…</code>
<br />
<code><br /></code>
The <code>ARJUNA016037</code> the warning was a topic in various discussions<br />
<br />
<ul>
<li><a href="https://planet.jboss.org/post/norecoveryxa">https://planet.jboss.org/post/norecoveryxa</a></li>
<li><a href="https://developer.jboss.org/wiki/TxNonSerializableXAResource">https://developer.jboss.org/wiki/TxNonSerializableXAResource</a></li>
</ul>
The warning is shown again and again in the application log. It's shown each time the
periodic recovery is running – as it informs there is a record and I don't know what to do with that.<br />
<div>
<br />
<i><b>NOTE:</b></i>
The periodic recovery runs <a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L45">by default</a>
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java#L948">every 2 minutes</a>.<br />
<br />
<h4>
Now, what we can do with that?</h4>
<br />
Fortunately, there is an <a href="https://issues.jboss.org/browse/JBTM-860">enhancement</a>
of the recovery processing in the Narayana for some time already.
When the participant driver (ie. resource manager "deployed" in the same JVM) implements
<a href="https://github.com/jbosstm/jboss-transaction-spi/blob/7.6.0.Final/src/main/java/org/jboss/tm/XAResourceWrapper.java">the Narayna SPI XAResourceWrapper</a>
it provides the information what resource is the owner of the participant record.
Narayana periodic recovery is then capable to deduce if the orphaned object store record
belongs to the particular participant's resource local storage.
Then it can assume that the participant committed already its work.
Narayana can update its own object store and periodic recovery stops to show the warnings.
<br />
<a href="https://github.com/apache/activemq-artemis/blob/2.9.0/artemis-service-extensions/src/main/java/org/apache/activemq/artemis/service/extensions/xa/ActiveMQXAResourceWrapperImpl.java">An example of the usage of the SPI</a>
is in the Active MQ Artemis RA.
<br />
<br />
<h3>
Transaction processing failures</h3>
Back to the transaction processing failures <i>(JVM crash, network failure, internal participant error)</i>.
<br />
As mentioned the "clean failures" can be automatically handled by the periodic recovery.
But the "clean" failures are not the only ones you can experience.
The XA protocol permits a heuristic failure. Those are failures which occurs
when the participant does not follow the XA protocol.
Such failures are not automatically recoverable by periodic recovery.
Human intervention is needed.<br />
<br />
Such failures occur mostly because of an internal error at the remote participant.
An example of such failure could be that the transaction manager commands the resource to commit
with <code>XAResource.commit</code> call. But the resource manager responds
that it already rolled-back the resource transaction arbitrarily. In such a case,
Narayana saves this unexpected state into the object store.
The transaction is marked having the heuristic outcome.
And the periodic recovery observes the heuristic record
in the object store and informs about it during each cycle.
<br />
Now, it's the responsibility of the administrator to get an understanding
of the transaction state and handle it.
<br />
But if he does not process such a transaction for a very long time then...
<br />
<br />
<h3>
Expiry scanners</h3>
...then we are back at the track to the expiry scanners.
<br />
What does mean that a record stays in the object for a very long time?<br />
<br />
The "very long time" is by default
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L54">12 hours</a>
for Narayana. It's the default time after when the garbage collection process starts.
This garbage collection is the responsibility of the expiry scanners.
The purpose is cleaning the object store from the long staying records.
When there is a record left in the heuristic state for 12 hours in the object store
or there is a record without the matching participant's resource local storage info in the object store
then the expiry scanner handles it.
The purpose of such handling causes is the periodic recovery stops to observe the existence of such in-doubt participant
and subsequently to stop complaining about the existence of the record.
<br />
<br />
Handling a record means moving a record to a different place
(changing the type of the record and placing the record to a different place in the hierarchical structure)
or removing the record completely from the object store.
<br />
<br />
<h4>
Available implementations of the expiry scanner</h4>
For the JTA transaction types, there are following expiry scanners available in Narayana
<br />
<ul>
<li><a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/AtomicActionExpiryScanner.java">AtomicActionExpiryScanner</a>
: moving records representing the prepared transaction (<code>AtomicAction</code>) to the inferior hierarchy place
named <code>/Expired</code>.
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/ExpiredTransactionStatusManagerScanner.java">ExpiredTransactionStatusManagerScanner</a>
: removing records about connection setup for the status manager.
This record is not connected with transaction processing and represents Narayana runtime data.
</li>
</ul>
<br />
For the JTS transaction types, there are following expiry scanners available in Narayana
<br />
<ul>
<li><a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTS/jts/classes/com/arjuna/ats/internal/jts/recovery/transactions/ExpiredToplevelScanner.java">ExpiredToplevelScanner</a>
Removing <code>ArjunaTransactionImple/AssumedCompleteTransaction</code> record from the object store.
The <code>AssumedCompleteTransaction</code> originates from the type <code>ArjunaTransactionImple</code>
and is moved to the assumed type by the JTS periodic recovery processing.
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTS/jts/classes/com/arjuna/ats/internal/jts/recovery/transactions/ExpiredServerScanner.java">ExpiredServerScanner</a>
Removing <code>ArjunaTransactionImple/AssumedCompleteServerTransaction</code> record from the object store.
The <code>AssumedCompleteServerTransaction</code> originates from the type <code>ArjunaTransactionImple/ServerTransaction/JCA</code>
and is moved to the assumed type by the JTS periodic recovery processing.
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTS/jts/classes/com/arjuna/ats/internal/jts/recovery/contact/ExpiredContactScanner.java">ExpiredContactScanner</a>
: Scanner removes the records which let the recovery manager know what Narayana instance belongs to which JVM.
This record is not connected with transaction processing and represents Narayana runtime data.</li>
</ul>
<br />
<h4>
</h4>
<h4>
Setup of expiry scanners classes</h4>
<a href="https://jbossts.blogspot.com/2018/01/narayana-periodic-recovery-of-xa.html#configuration">As explained elsewhere</a>
Narayana can be set up either with system properties
passed directly to the Java program or defined
in the file descriptor <code>jbossts-properties.xml</code>.
If you run the WildFly application server the system properties can be
defined at the command line with <code>-D…</code> when starting application
server with <code>standalone.sh/bat</code> script.
Or they can be persistently added
into the <code>bin/standalone.conf</code> config file.
<br />
The class names of the expiry scanners that will be active after Narayana initialization
can be defined by property
<code>com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean.expiryScannerClassNames</code>
or <code>RecoveryEnvironmentBean.expiryScannerClassNames</code> (named differently, doing the same service).
The property then contains the fully qualified class names of implementation of <code>ExpiryScanner</code> interface.
The class names are separated with space or an empty line.
<br />
An example of such settings could be seen
<a href="https://github.com/jbosstm/quickstart/blob/5.9.5.Final/agroal/src/main/resources/jbossts-properties.xml#L84">at Narayana quickstarts</a>.
Or when it should be defined directly here it's
<br />
<pre><code>-DRecoveryEnvironmentBean.expiryScannerClassNames="com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner com.arjuna.ats.internal.arjuna.recovery.AtomicActionExpiryScanner"</code></pre>
<br />
<i><b>NOTE:</b></i> when you configure the WildFly app server then you are allowed to use
only the shortened property name of <code>-DRecoveryEnvironmentBean.expiryScannerClassNames=…</code>.
The longer variant does not work because of the way the issue
<a href="https://issues.jboss.org/browse/WFLY-951">WFLY-951</a> was implemented.
<br />
<i><b><br /></b></i>
<i><b>NOTE2:</b></i> when you are running the WildFly app server then the expired
scanners enabled by default could be observed by looking into the source code
at <a href="https://github.com/wildfly/wildfly/blob/17.0.0.Final/transactions/src/main/java/org/jboss/as/txn/service/ArjunaRecoveryManagerService.java#L112">ArjunaRecoveryManagerService</a>
(consider variants for JTA and JTS modes).
<br />
<br />
<h4>
Setup of expiry scanners interval</h4>
To configure the time interval after the "orphaned" record is handled
as the expired one you can use the property
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L54">the property with the name</a>
<code>com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean.expiryScanInterval</code>
or <code>RecoveryEnvironmentBean.expiryScanInterval</code>. The value could be a positive whole number.
Such number defines that the records expire after that number of hours.
If you define the value as
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/ExpiredEntryMonitor.java#L225">a negative whole number</a>
then the first run of the expire scanner run skipped.
Next run of the expire scanner expires the records after that (positive) number of hours.
If you define the value to be <code>0</code> then records are never handled by expiry scanners.
<br />
<br />
<br />
That's all in terms of this article. Feel free to ask a question here or
at our forum at <a href="https://developer.jboss.org/en/jbosstm">https://developer.jboss.org/en/jbosstm</a>.
<br />
<br /></div>
Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8686578724458335326.post-67921767139400243122019-04-29T15:56:00.000+01:002019-04-29T17:05:09.437+01:00JTA and CDI integration<p>
The <a href="https://github.com/jbosstm/narayana/releases/tag/5.9.5.Final">Narayana release 5.9.5.Final</a>
comes with few nice CDI functionality enhancements.
This blogpost introduces these changes while placing them to the context
of the JTA and CDI integration, particularly with focus to <a href="http://weld.cdi-spec.org">Weld</a>.
</p>
<h2>TL;DR</h2>
<p>
The fastest way to find out the way of using the JTA with the CDI is walking through
<a href="https://github.com/jbosstm/quickstart/tree/master/jta-1_2-standalone">the Narayana CDI quickstart</a>.
</p>
<h2>JTA and CDI specifications</h2>
<p>
JTA version 1.2 was published in 2013. The version introduced the integration of JTA with CDI.
The <a href="https://jcp.org/en/jsr/detail?id=907">specification</a> came with the definition of annotations
<a href="https://github.com/eclipse-ee4j/jta-api/blob/initial-contribution/src/main/java/javax/transaction/Transactional.java"><code>javax.transaction.Transactional</code></a>
and <a href="https://github.com/eclipse-ee4j/jta-api/blob/initial-contribution/src/main/java/javax/transaction/TransactionScoped.java"><code>javax.transaction.TransactionScoped</code></a>.
Those two provide a way for transaction boundary definition
and for handling application data bounded to the transaction.
</p>
<p>
Narayana, as the implementation of the JTA specification, provides those capabilities
in the <a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTA/cdi/pom.xml">CDI maven module</a>.<br/>
Here we come with the maven coordinates:<br/>
<code><groupId>org.jboss.narayana.jta</groupId></code><br/>
<code><artifactId>cdi</artifactId></code>
</p>
<p>
The module brings
<a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTA/cdi/classes/com/arjuna/ats/jta/cdi/TransactionExtension.java">Narayana CDI extension</a>
to the user's project.
The extension installs interceptors which manage transactional boundaries
for method invocation annotated with <code>@Transactional</code>.
Then the extension defines a <a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTA/cdi/classes/com/arjuna/ats/jta/cdi/TransactionExtension.java#L72">transaction scope</a>
declared with the <code>@TransactionScoped</code> annotation.
</p>
<p>
On top of the functionality defined in the JTA specification, it's the CDI specification which defines
some more transaction-related features.
They are the <a href="http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#transactional_observer_methods">transactional observer methods</a>
and the definition of the <code>javax.transaction.UserTransaction</code>
<a href="http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#additional_builtin_beans">built-in bean</a>.
</p>
<p>
Let's summarize what that all means in practice.
</p>
<h3>@Transactional</h3>
<p>
With the use of the <code>@Transactional</code> annotation, transaction boundary
could be controlled declaratively. The use of the annotation is really similar
to <a href="http://docs.wildfly.org/16/Developer_Guide.html#transactions-in-enterprise-java-applications">the container-managed transactions in EJB</a>.
</p>
<p>
When the annotation is used for a bean or a method the Narayana CDI extension (CDI interceptor is used) verifies
the existence of the transaction context when the method is called. Based on the value of the <code>value</code> parameter
an appropriate action is taken. The <code>value</code> is defined from enumeration
<a href="https://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.TxType.html"><code>Transactional.TxType</code></a><br/>
For example when <code>@Transactional(Transactional.TxType.REQUIRES_NEW)</code> is used on the method
then on the start of its execution a new transaction is started. If the incoming method call contains an existing transaction
it's suspended during the method execution and then resumed after it finishes. For details about the other <code>Transactional.TxType</code>
values consider the <a href="https://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.TxType.html"><code>javadoc documentation</code></a>.
</p>
<p>
NOTE: be aware of the fact that for the CDI container can intercept the method call
the CDI managed instance has to be used. For example, when you want to use the
capability for calling an inner bean you must use the injection of the bean itself.
<pre><code class="java">@RequestScope
public class MyCDIBean {
@Inject
MyCDIBean myBean;
@Transactional(TxType.REQUIRED)
public void mainMethod() {
// CDI container does not wrap the invocation
// no new transaction is started
innerFunctionality();
// CDI container starts a new transaction
// the method uses TxType.REQUIRES_NEW and is called from the CDI bean
myBean.innerFunctionality();
}
@Transactional(TxType.REQUIRES_NEW)
private void innerFunctionality() {
// some business logic
}
}
</code></pre>>
</p>
<h3>@TransactionScoped</h3>
<p>
<code>@TransactionScoped</code> brings an additional scope type in addition to
<a href="http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#builtin_contexts">the standard built-in ones</a>.
A bean annotated with the <code>@TransactionScoped</code>, when injected,
lives in the scope of the currently active transaction. The bean remains
bound to the transaction even when it is suspended. On resuming the transaction
the scoped data are available again.
If a user tries to access the bean out of the scope of the active transaction
the <a href="https://docs.oracle.com/javaee/7/api/javax/enterprise/context/ContextNotActiveException.html">javax.enterprise.context.ContextNotActiveException</a>
is thrown.
</p>
<h3>Built-in UserTransaction bean</h3>
<p>
The CDI specification declares that the Java EE container
has to provide a bean for the <a href="https://docs.oracle.com/javaee/7/api/javax/transaction/UserTransaction.html">UserTransaction</a>
can be <a href="https://docs.oracle.com/javaee/7/api/javax/inject/Inject.html">@Inject</a>ed.
Notice that the standalone CDI container has no obligation to provide
such bean. The availability is expected for the Java EE container.
In <a href="https://weld.cdi-spec.org">Weld</a>, the integration for the Java EE container is provided
through the SPI interface
<a href="https://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/transaction/spi/TransactionServices.java">TransactionServices</a>.
</p>
<p>
If somebody wants to use the Weld integrated with Narayana JTA implementation
in a standalone application he needs to implement
<a href="https://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/transaction/spi/TransactionServices.java">this</a>
SPI interface (see more below).
</p>
<h3>Transaction observer methods</h3>
<p>
The feature of
<a href="http://www.next-presso.com/2014/06/you-think-you-know-everything-about-cdi-events-think-again/#transactional-observer-methods">the transaction observer methods</a>
allows defining an observer
with the definition of the <code>during</code> parameter
at <a href="https://docs.oracle.com/javaee/7/api/javax/enterprise/event/Observes.html">@Observes</a> annotation.
<code>During</code> takes a value from the <a href="https://docs.oracle.com/javaee/7/api/javax/enterprise/event/TransactionPhase.html">TransactionPhase</a>
enumeration.
The <code>during</code> value defines when the event will be delivered
to the observer. The event is fired during transaction processing in the business logic
but then the delivery is deferred until transaction got status defined by the <code>during</code>
parameter.<br/>
The <code>during</code> parameter can obtain values <code>BEFORE_COMPLETION</code>, <code>AFTER_COMPLETION</code>,
<code>AFTER_FAILURE</code>, <code>AFTER_SUCCESS</code>.
Using value <code>IN_PROGRESS</code> means the event is delivered to observer immediately when it's fired.
It behaves like there is no <code>during</code> parameter used.
</p>
<p>
The implementation is based on the registration of
<a href="https://docs.oracle.com/javaee/7/api/javax/transaction/Synchronization.html">the transaction synchronization</a>.
When the event is fired there is registered a special new synchronization which is invoked by the transaction manager afterwards.
The registered CDI synchronization code then manages to launch the observer method to deliver the event.
</p>
<p>
For the <code>during</code> parameter working and for the events being deferred Weld requires
integration through
the <a href="https://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/transaction/spi/TransactionServices.java">TransactionServices</a> SPI.
The interface defines a method which provides makes for Weld possible to register the transaction synchronization.
If the integration with the <code>TransactionServices</code> is not provided then the user can still use the <code>during</code>
parameter in his code. But(<b>!</b>) no matter what <code>TransactionPhase</code> value is used
the event is not deferred but it's immediately delivered to the observer.
The behaviour is the same as when the <code>IN_PROGRESS</code> value is used.
</p>
<p>
Maybe it could be fine to clarify who fires the event. The event is fired by the user code. For example, take a look at the example
<a href="http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_transactional_observers">in the Weld documentation</a>.
The user code injects an event and fires it when considers it necessary.
<pre><code class="java">@Inject @Any Event<Product> productEvent;
...
public void persist(Product product) {
em.persist(product);
productEvent.select(new AnnotationLiteral<Created>(){}).fire(product);
}
</code></pre>
The observer is defined in the standard way and using <code>during</code>
for the event delivery to be deferred until the time the transaction is finished with success.
<pre><code class="java"></code>void addProduct(@Observes(during = AFTER_SUCCESS) @Created Product product) {
...
}
</code></pre>
</p>
<h3>A bit more about TransactionServices: Weld and JTA integration</h3>
<p>
As said for the integration of the Weld CDI to JTA it's needed to implement
the <a href="https://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/transaction/spi/TransactionServices.java">TransactionServices</a>
SPI interface.
The interface gives the Weld the chance to gain the <code>UserTransaction</code>
thus the built-in bean can provide it when it's <code>@Inject</code>ed.
It provides the way to register transaction synchronization
for an event could be deferred until particular transaction status occurs.
Up to that, it demands the implementation of the method <code>isTransactionActive</code>.
The <code>TransactionScoped</code> is active only when there is some
active transaction. This way the Weld is able to obtain the transaction activity state.
</p>
<p>
Regarding the implementation, you can look at how the interface <code>TransactionServices</code>
<a href="https://github.com/wildfly/wildfly/blob/16.0.0.Final/weld/transactions/src/main/java/org/jboss/as/weld/services/bootstrap/WeldTransactionServices.java">is implemented in WildFly</a>
or in the more standalone way
<a href="https://github.com/smallrye/smallrye-context-propagation/blob/1.0.1/jta/src/test/java/io/smallrye/context/inject/TransactionServicesImpl.java">for SmallRye Context Propagation</a>.
</p>
<h2>A new Narayana CDI features</h2>
<p>
Narayana brings two new CDI JTA integration capabilities,
up to those described above.
</p>
<p>
The first enhancement is the addition of the transactional scope events. Up to now, Narayana
did not fire
<a href="http://www.next-presso.com/2014/06/you-think-you-know-everything-about-cdi-events-think-again/#built-in-events-linked-to-scope-lifecycle-cdi-1-1">the scope events for the @TransactionScoped</a>.
From now there is fired the scope events automatically by Narayana. The user
can observe the <a href="https://docs.oracle.com/javaee/7/api/javax/enterprise/context/Initialized.html">initialization</a>
and the <a href="https://docs.oracle.com/javaee/7/api/javax/enterprise/context/Destroyed.html">destruction</a> of the transaction scope.
The code for the observer could be like
<pre><code class="java">void transactionScopeActivated(
@Observes @Initialized(TransactionScoped.class) final Transaction event,
final BeanManager beanManager) {
...
}
</code></pre>
The event payload for the <code>@Initialized</code> is the <code>javax.transaction.Transaction</code>,
for the <code>@Destroyed</code> is just the <code>java.lang.Object</code>
(when the transaction scope is destroyed there is no active transaction anymore).<br/>
As the Narayana implements the CDI in version 1.2 in these days there is not fired an event for <code>@BeforeDestroy</code>.
That scope event was introduced in the CDI version 2.0.
</p>
<p>
The second enhancement is the addition of two built-in beans which can be <code>@Inject</code>ed in the user code.
Those are beans <code>TransctionManager</code> and <code>TransactionSynchronizationRegistry</code>.
</p>
<p>
The implementation gives priority to the JNDI binding. If there is bound
<code>TransactionManager</code>/<code>TransactionSynchronizationRegistry</code>
in the JNDI then such instance is returned at the injection point.<br/>
If the user defines his own CDI bean or a CDI producer which provides an instance
of those two classes then such instance is grabbed for the injection.<br/>
As the last resort, the default Narayana implementation of both classes is used.
You can consider
the <a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/TransactionManagerImple.java">TransactionManagerImple</a>
and the <a href="https://github.com/jbosstm/narayana/blob/5.9.5.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/TransactionSynchronizationRegistryImple.java">TransactionSynchronizationRegistryImple</a>
to be used.
</p>
<h2>Using the transactional CDI extension</h2>
<p>
The easiest way to check the integration in the action is to run our
<a href="https://github.com/jbosstm/quickstart/tree/master/jta-1_2-standalone">JTA standalone quickstart</a>.
You can observe the implementation of the Weld SPI interface
<a href="https://github.com/jbosstm/quickstart/blob/master/jta-1_2-standalone/src/test/java/org/jboss/narayana/quickstarts/jta/cdi/CDITransactionServices.java">TransactionServices</a>.
You can check
<a href="https://github.com/jbosstm/quickstart/blob/master/jta-1_2-standalone/src/main/java/org/jboss/narayana/quickstarts/jta/RequiredCounterManager.java">the use of the observers</a>,
both the transaction observer methods and the transactional scoped observers.
Up to that, you can see the use of
<a href="https://github.com/jbosstm/quickstart/blob/master/jta-1_2-standalone/src/main/java/org/jboss/narayana/quickstarts/jta/Counter.java">the transaction scope</a>
and use of the injection
for <a href="https://github.com/jbosstm/quickstart/blob/master/jta-1_2-standalone/src/main/java/org/jboss/narayana/quickstarts/jta/RequiredCounterManager.java">the TransactionManager</a>.
</p>
<h2>Acknowledgement</h2>
<p>
Big thanks to <a href="https://about.me/lairdnelson">Laird Nelson</a>
who contributed the new CDI functionality enhancements to Narayana.
<br/>
And secondly thanks to <a href="https://github.com/manovotn">Matěj Novotný</a>.
for his help in understanding the CDI topic.
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-88574467868574229142018-10-19T15:57:00.003+01:002019-04-27T06:32:36.409+01:00Narayana integration with Agroal connection pool<p>
Project <a href="http://agroal.github.io" target="_blank">Agroal</a> defines itself as <i>“The natural database connection pool”</i>. And that’s what is it.
</p>
<p>
It was developed by <a href="https://github.com/barreiro" target="_blank">Luis Barreiro</a>. He works for WildFly as a performance engineer. This prefigures what you can expect – <a href="https://github.com/agroal/agroal.benchmark">a well performing</a> database connection pool. As Agroal comes from the porfolio of the WildFly projects it offers smooth integration with WildFly and <a href="https://github.com/agroal/agroal/tree/master/agroal-narayana">with Narayana</a> too.
</p>
<p>
In the previous posts we checked other connection pools that you can use with Narayana - either the <a href="https://jbossts.blogspot.com/2017/12/narayana-jdbc-transactional-driver.html">transactional driver provided by Narayana</a> or <a href="https://jbossts.blogspot.com/2018/05/narayana-jdbc-integration-for-tomcat.html">DBCP2</a> which is nicely integrated to be used with Narayana in Apache Tomcat. Another option is the use of the <a href="http://www.ironjacamar.org">IronJacamar</a> which lives in the long-termed brotherhood with Narayana. All those options are nicely documented in <a href="https://github.com/jbosstm/quickstart/">our quickstarts</a>.
</p>
<p>
Agroal is a party member and you should consider to check it. Either when running standalone application with Narayana or when you run on WildFly. Let’s take a look how you can use it in the standalone application first.
</p>
<h2>Agroal with Narayana standalone</h2>
<p>
In case you want to use the Agroal JDBC pooling capabilities with Narayana in your application you need to configure the Agroal datasource to know
<ul>
<li>how to grab the instance of the Narayana transaction manager</li>
<li>where to find <a href="https://docs.oracle.com/javaee/7/api/javax/transaction/TransactionSynchronizationRegistry.html" target="_blank">the synchronization registry</a></li>
<li>how to register resources to Narayana recovery manager</li>
</ul>
</p>
<h3>Narayana setup</h3>
<p>
First we need to gain all the mentioned Narayana objects which are then passed to Agroal
which ensures the integration by calling the Narayana API at appropriate moments.
<pre><code class="java">// gaining the transction manager and synchronization registry
TransactionManager transactionManager
= com.arjuna.ats.jta.TransactionManager.transactionManager();
TransactionSynchronizationRegistry transactionSynchronizationRegistry
= new com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple();
// intitialization of recovery manager
RecoveryManager recoveryManager
= com.arjuna.ats.arjuna.recovery.RecoveryManager.manager();
recoveryManager.initialize();
// recovery service provides binding for hooking the XAResource to recovery process
RecoveryManagerService recoveryManagerService
= new com.arjuna.ats.jbossatx.jta.RecoveryManagerService();
recoveryManagerService.create();
</code></pre>
</p>
<h3>Agroal integration</h3>
<p>
Now we need to pass the Narayana's object instances to Agroal.
With that being done we can obtain a JDBC <code>Connection</code>
which is backed by the transaction manager.
<pre><code class="java">
AgroalDataSourceConfigurationSupplier configurationSupplier
= new AgroalDataSourceConfigurationSupplier()
.connectionPoolConfiguration(cp -> cp
.transactionIntegration(new NarayanaTransactionIntegration(
transactionManager, transactionSynchronizationRegistry,
"java:/agroalds1", false, recoveryManagerService))
cf.connectionFactoryConfiguration(cf ->
.jdbcUrl("jdbc:h2:mem:test")
.principal(new NamePrincipal("testuser"))
.credential(new SimplePassword("testpass"))
.recoveryPrincipal(new NamePrincipal("testuser"))
.recoveryCredential(new SimplePassword("testpass"))
.connectionProviderClassName("org.h2.jdbcx.JdbcDataSource"))
.maxSize(10)
);
AgroalDataSource ds1 = AgroalDataSource.from(configurationSupplier);
transactionManager.begin();
conn1 = ds1.getConnection();
...
</code></pre>
</p>
<p>
Those are steps needed for the standalone application to use Narayana and Agroal. The working code example
could be seen in the Narayana quickstart at
<a href="https://github.com/jbosstm/quickstart/blob/master/agroal/src/main/java/io/narayana/AgroalDatasource.java" target="_blank">github.com/jbosstm/quickstart#agroal - AgroalDatasource.java</a>
</p>
<h2>Agroal XA datasource in WildFly</h2>
<p>
If you want to use the power of Narayana in the WildFly application you need XA participants that Narayana can drive. From Agroal perspective you need to define a xa datasource which you use (linked via JNDI name) in your application.
</p>
<p><i>
DISCLAIMER: for you can use the Agroal capabilities integrated with Narayana you will need to run WildFly 15 or later.
Currently only WildFly 14 is available so for testing this you need to build the WildFly from sources by yourself.
The good message is that’s an easy task – see at <a href="https://github.com/wildfly/wildfly/#building">https://github.com/wildfly/wildfly/#building</a>.
</i></p>
<p>
Agroal datasource subsystem is not available by default in the <code>standalone.xml</code> file so you need to enable that extension. When you run the <code>jboss cli</code>
commands then you do it like this
</p>
<p>
<pre><code class="bash">cd $JBOSS_HOME
./bin/jboss-cli.sh -c
# jboss-cli is started, run following command there
/extension=org.wildfly.extension.datasources-agroal:add
/subsystem=datasources-agroal:add()
:reload
</code></pre>
</p>
<p>
From now you can work with the <code>datasources-agroal</code> subsystem. For you can create the <code>xa-datasource</code> definition you need to have a driver which the datasource will use. The driver has to define it’s XA connection provider.
<p>
<p>
<i>NOTE:</i> if you want to check what are options for the Agroal configuration in the jboss cli then read the resource description with command
<code>/subsystem=datasources-agroal:read-resource-description(recursive=true)</code>
</p>
<p>
Agroal driver definition works only with drivers <a href="https://docs.jboss.org/author/display/WFLY10/Class+Loading+in+WildFly" target="_blank">deployed as modules</a>.
You can’t just copy the driver jar to <code>$JBOSS_HOME/standalone/deployments</code> directory but you need to create a module under <code>$JBOSS_HOME/modules</code> directory.
See details either by creating <code>module.xml</code> <a href="http://www.adam-bien.com/roller/abien/entry/installing_oracle_jdbc_driver_on" target="_blank">by yourself</a> or the recommended way
is using the <code>jboss cli</code> with command
<pre><code class="bash">module add --name=org.postgresql
--resources=/path/to/jdbc/driver.jar --dependencies=javax.api,javax.transaction.api
</code></pre>
</p>
<p>
<i>NOTE:</i> The command uses the name of the module <code>org.postgresql</code> as I will demonstrate adding the xa datasource for the PostgreSQL database.
</p>
<p>
When the module is added we can declare the Agroal’s driver.
<pre><code class="bash">/subsystem=datasources-agroal/driver=postgres:add(
module=org.postgresql, class=org.postgresql.xa.PGXADataSource)
</code></pre>
</p>
<p>
We’ve used the class <code>org.postgresql.xa.PGXADataSource</code> as we want to use it as XA datasource. When class is not defined then standard jdbc driver for PostgresSQL is used (<code>org.postgresql.Driver</code>) as declared <a href="https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/resources/META-INF/services/java.sql.Driver" target="_blank">in the <code>META-INF/services/java.sql.Driver</code> file</a>.
</p>
<p>
<i>NOTE:</i> If you would declare the driver without the XA datasource being defined and then you try to add it to XA datasource definition you will get an error
<pre><code class="bash">/subsystem=datasources-agroal/driver=non-xa-postgres:add(module=org.postgresql)
/subsystem=datasources-agroal/xa-datasource=AgroalPostgresql:add(
connection-factory={driver=non-xa-postgres},...)
{
"outcome" => "failed",
"failure-description" => {"WFLYCTL0080: Failed services" => {"org.wildfly.data-source.AgroalPostgresql"
=> "WFLYAG0108: An xa-datasource requires a javax.sql.XADataSource as connection provider. Fix the connection-provider for the driver"}
},
"rolled-back" => true
}
</code></pre>
</p>
<p>
When the JDBC driver module is defined we can create the Agroal XA datasource. The bare minimum of attributes you have to define is shown in the following command
<pre><code class="bash">/subsystem=datasources-agroal/xa-datasource=AgroalPostgresql:add(
jndi-name=java:/AgroalPostgresql, connection-pool={max-size=10}, connection-factory={
driver=postgres, username=test, password=test,url=jdbc:postgresql://localhost:5432/test})
</code></pre>
</p>
<p>
<i>NOTE:</i> this is the most simple way of define the credentials for the connection to database. If you consider more sophisticated method, than just username/password as clear strings saved in the standalone.xml, take a look at the <a href="https://docs.jboss.org/author/display/WFLY/WildFly+Elytron+Security" target="_blank">Elytron capabilities</a>.
</p>
<p>
To check if the WildFly Agroal datasource is able to connect to the database you can use test-connection command
<pre><code class="bash">/subsystem=datasources-agroal/xa-datasource=AgroalPostgresql:test-connection()
</code></pre>
</p>
<p>
If you are insterested how the configuration looks as a xml element in <code>standalone.xml</code> configuration file then the Agroal subsystem with PostgreSQL XA datasource definition would look like
<pre><code class="xml"><subsystem xmlns="urn:jboss:domain:datasources-agroal:1.0">
<xa-datasource name="AgroalPostgresql" jndi-name="java:/AgroalPostgresql">
<connection-factory driver="postgres" url="jdbc:postgresql://localhost:5432/test"
username="test" password="test"/>
<connection-pool max-size="10"/>
</xa-datasource>
<drivers>
<driver name="postgres" module="org.postgresql" class="org.postgresql.xa.PGXADataSource"/>
</drivers>
</subsystem>
</code></pre>
</p>
<p>
If you want use the Agroal non-xa datasource as commit markable resource (CMR) it’s possible too. You need to create a standard datasource and define it as connectable. For more information what the commit markable resource means and how it works <a href="https://jbossts.blogspot.com/2018/06/narayana-commit-markable-resource.html" target="_blank">check our previous blogpost about CMR</a>.
<pre><code class="xml"><subsystem xmlns="urn:jboss:domain:datasources-agroal:1.0">
<datasource name="AgroalPostgresql" connectable="true" jndi-name="java:/AgroalPostgresql"
statistics-enabled="true">
<connection-factory driver="postgres" url="jdbc:postgresql://localhost:5432/test"
username="test" password="test"/>
<connection-pool max-size="10"/>
</datasource>
<drivers>
<driver name="postgres" module="org.postgresql" class="org.postgresql.Driver"/>
</drivers>
</subsystem>
</code></pre>
</p>
<p>
<i>NOTE:</i> In addition to this configuration of Agroal datasource you need to enable the CMR in the transaction subsystem too
– <a href="https://jbossts.blogspot.com/2018/06/narayana-commit-markable-resource.html" target="_blank">check the blogpost for detailed info</a>.
</p>
<h2>Summary</h2>
<p>
This blogpost showed way how to configure Agroal JDBC pooling library and how to integrate it with Narayana.<br/>
The code example is part of the Narayana quickstart and you can check it at
<a href="https://github.com/jbosstm/quickstart/tree/master/agroal">https://github.com/jbosstm/quickstart/tree/master/agroal</a>
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-89017408426649501192018-09-09T20:12:00.000+01:002018-09-09T20:12:44.545+01:00Tips on how to evaluate STM implementations<head>
<link href="https://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css"></link>
<link href="https://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script>
<script src="https://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js" type="text/javascript"></script>
<script language="javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf';
SyntaxHighlighter.all();
</script>
</head>
Software Transactional Memory (STM) is a way of providing transactional behaviour for threads operating on shared memory. The transaction is an atomic and isolated set of changes to memory such that prior to commit no other thread sees the memory updates and after commit the changes appear to take effect instantaneously so other threads never see partial updates but on abort all of the updates are discarded.<br />
<br />
Unlike other models such as XA, OTS, JTA, WS-AT etc, with STM there is no accepted standard for developers to program against. Consequently the various implementations of STM differ in important respects which have consequences for how application developers build their software. I recently came upon an excellent book on <a href="https://www.morganclaypool.com/doi/abs/10.2200/S00070ED1V01Y200611CAC002">Transactional Memory</a> where the authors James Larus and Ravi Rajwar presented a taxonomy of features and characteristics that can be used to differentiate the various STM implementations from each other. In this and subsequent blogs I will explain the taxonomy and identify where the <b>Narayana STM</b> solution (which was introduced in Mark Little's <a href="http://jbossts.blogspot.com/2011/06/stm-arjuna.html">initial blog on the topic</a>) fits into it. Towards the end of the series I will include some tips, best practices and advice on how you can get the most out of the Narayana implementation of STM.<br />
<br />
In this first article I will cover isolation, nesting and exception handling. In later articles I will discuss topics such as conflict detection and resolution, transaction granularity, concurrency control etc.
<br />
<br />
By way of motivation, why would one want to use STM in favour of other transaction models and concurrency control mechanisms:<br />
<ul>
<li>The STM approach of mutating data inside of a transaction has some nice features:</li>
<ul>
<li>It is less error prone since the demarcation of an atomic block of code is primitive but other synchronisation approaches are many and varied. Techniques such as locks, semaphores, signals etc are tricky to get right, for example the programmer must ensure that accesses are protected with the correct locks and in the correct order. With conventional concurrency control, imagine trying reverse all the changes made during a computation if a problem such as deadlock or data race is detected, whereas code changes that are protected by STM can be aborted in a single statement.</li>
<li>Transactional updates make it easier for the programmer to reason about his code (it is clear how different threads affect each other) and data (because it simplifies the sharing of state between threads).</li>
</ul>
</ul>
<ul>
<li>The declarative approach (where the programmer simply marks which code blocks are transactional) means concurrent programming is more intuitive with no explicit locks or synchronisation to worry about.</li>
<li>Can perform much better than fine grained locking (which can lead to deadlock) and coarse grained locking (which inhibits concurrency):</li>
<ul>
<li>If a thread takes a lock and is context switched or incurs cache misses or page faults etc then other threads that need the lock are stalled until the thread is rescheduled or until the needed data is retrieved.</li>
<li>With STM, updates can be batched up and speculatively committed together.</li>
<li>The runtime manages lock acquisition and release and resolves conflicts (using approaches such as timeouts and retries).</li>
</ul>
<li>It is easier to compose operations using a technique called nesting (traditionally composing two operations can produce concurrency problems unless one analyses in detail the locking approach used by those operations).</li>
</ul>
<div>
<h2>
Properties of a STM system</h2>
</div>
In the following I will describe the design choices available to STM systems in general and in particular I will illustrate the choices made by the <b>Narayana STM</b> implementation using code examples. The examples <a href="https://issues.jboss.org/browse/JBTM-3058">will be made available</a> in the <b>Narayana STM</b> test suite so that you can also experiment with the particular properties of the implementation. Each of the examples will be using the same transactional object which is defined as follows:<br />
<div>
<br /></div>
<pre class="brush: java"> @Transactional
public interface AtomicInt {
int get() throws Exception;
void set(int value) throws Exception;
}
public class AtomicIntImpl implements AtomicInt {
private int state;
@ReadLock
public int get() throws Exception {
return state;
}
@WriteLock
public void set(int value) throws Exception {
state = value;
}
}
</pre>
<br />
The @Transactional annotation on the AtomicInt interface tells the system that instances of the interface are candidates to be managed by the STM system.
The implementation of the interface defines a pair of methods for reading and writing the the shared state (by default all state is
tracked but this default can be overridden via the @NotState annotation).<br />
<br />
<h3>
Property 1: Interaction with non transactional code</h3>
If uncommitted transactional memory updates are visible to non-transactional code and vice-versa (i.e. updates made by non-transactional code are visible to running transactions) then the isolation model is said to be weak. On the other hand if non-transactional accesses are upgraded to a transactional access then the model is said to be strong.<br />
<br />
The weak access model, although common, can lead to data races. A data race occurs if two threads T1 and T2 access memory, T1 for writing, say, and the other for reading then the value of the memory read is indeterminate. If, for example T1 writes data inside a transaction and T2 reads that data, then if T1 aborts but T2 has made a decision based on the value it read then we have an incorrect program since aborted transactions must not have side effects (recall the "all or nothing" characteristic of atomicity).<br />
<br />
<b>Narayana STM</b> follows the weak isolation model. The following test updates shared memory inside a transaction and then triggers a thread to perform non-transactional reads and writes on it while the transaction is still running. The test shows that the two threads interfere with each other producing indeterminate results:<br />
<pre class="brush: java"> public void testWeakIsolation() throws Exception {
AtomicIntImpl aiImple = new AtomicIntImpl();
// STM is managed by Containers. Enlisting the above implementation
// with the container returns a proxy which will enforce STM semantics
AtomicInt ai = new RecoverableContainer<atomicint>().enlist(aiImple);
AtomicAction tx = new AtomicAction();
// set up the code that will access the memory outside of a transaction
Thread ot = new Thread(() -> {
try {
synchronized (tx) {
tx.wait(); // for the other thread to start a transaction
// weak isolation implies that this thread (which is running
// outside of a transaction) can observe transactional updates
assertEquals(2, aiImple.get()); // the other thread set it to 2
aiImple.set(10); // this update is visible to transactional code
} catch (Exception e) {
e.printStackTrace();
}
});
ot.start();
ai.set(1); // initialise the shared memory
tx.begin(); // start a transaction
{
ai.set(2); // conditionally set the value to 2
synchronized (tx) {
tx.notify(); // trigger non-transactional code to update the memory
}
// weak isolation means that this transactional code may see the
// changes made by the non transactional code
assertEquals(10, ai.get()); // the other thread set it to 10
tx.commit(); // commit the changes made to the shared memory
}
// changes made by non transactional code are still visible after commit
assertEquals(10, ai.get());
assertEquals(aiImple.get(), ai.get());
}
</atomicint></pre>
<div>
<br />
As an aside, notice in this example that the code first had to declare the shared data using the @Transactional annotation and then had to access it via a proxy returned from a RecoverableContainer. Some systems introduce new keywords into the language that demarcate the atomic blocks and in such systems any memory updates made by the atomic block would be managed by the STM implementation. That type of system takes some of the burden of ensuring correctness away from the programmer but are harder to implement (for example a common technique requires compiler extensions).<br />
<br />
<h3>
Property 2: Nested transactions</h3>
<div>
A nested transaction (the child) is one that is started in the context of an outer one (the parent). The child sees the changes made by the parent. Aborting the parent will abort each child. A parent that does not have any parents is called top level.</div>
<div>
<br /></div>
<div>
The effects of committing/aborting either transaction (the child or parent) and the visibility of changes depend upon which model is being used:<br />
<br /></div>
<h4>
Flattened:</h4>
<div>
<ul>
<li>The parent and child transactions see each others updates.</li>
<li>If the child aborts the parent aborts too.</li>
<li>Changes made by the child only become visible to other threads when the parent commits</li>
</ul>
</div>
<div>
Pros - easy to implement</div>
<div>
Cons - breaks composition (if the child aborts it causes all work done by the parent transaction to abort)<br />
<br /></div>
<h4>
Closed Nested</h4>
<div>
<ul>
<li>Changes are hidden from the parent transaction (and from other transactions) until the child commits, at which time any changes made by the child become part of the parent transactions' set of updates (therefore, in contrast to open nested transactions, other transactions will not see the updates until the parent commits);</li>
<li>aborting the child does not abort the parent;</li>
</ul>
</div>
Pros - Is arguably the most natural model for application designers<br />
<br />
<h4>
Open Nested</h4>
<div>
<ul>
<li>When the child transaction commits, all other transactions see the updates even if the parent aborts which is useful if we want unrelated code to make permanent changes during the transaction even if the parent aborts.</li>
</ul>
<div>
Pros - enables work to be made permanent even if the parent aborts (for example logging code made by the child)</div>
<div>
<br /></div>
<b>Narayana STM</b> follows the closed model as is demonstrated by the following test case:</div>
<pre class="brush: java"> public void testIsClosedNestedCommit() throws Exception {
AtomicInt ai = new RecoverableContainer<atomicint>().enlist(new AtomicIntImpl());
AtomicAction parent = new AtomicAction();
AtomicAction child = new AtomicAction();
ai.set(1); // initialise the shared memory
parent.begin(); // start a top level transaction
{
ai.set(2); // update the memory in the context of the parent transaction
child.begin(); // start a child transaction
{
ai.set(3); // update the memory in a child transaction
// NB the parent would still see the value as 2
// (not shown in this test)
child.commit();
}
// since the child committed the parent should see the value as 3
assertEquals(3, ai.get());
// NB other transactions would not see the value 3 however until
// the parent commits (not demonstrated in this test)
}
parent.commit();
assertEquals(3, ai.get());
}
</atomicint></pre>
<h4>
Isolation amongst child transactions</h4>
<div>
The concept of isolation applies to nested transactions as well as to top level transactions. It seems most natural for siblings to use the same model as is used for isolation with respect to other transactions (ie transactions that are not in ancestor hierarchy of a particular child). For example the CORBA Object Transaction Service (OTS) supports the closed model and children do not see each others updates until the parent commits.</div>
</div>
<br />
<h3>
Property 3: Exception Handling</h3>
<div>
On exception the options are to either terminate or ignore the exception or to use a mixture of both where the programmer tells the system which exceptions should abort and which ones should commit the transaction which is similar to what the JTA 1.2 spec provides with its <i>rollbackOn</i> and <i>dontRollbackOn</i> annotation attributes.</div>
<div>
<br /></div>
<div>
The <b>Narayana STM</b> implementation takes the view that the programmer is best placed to make decisions about what to do under exceptional circumstances. The following test demonstrates this behaviour:<br />
<pre class="brush: java"> public void testExceptionDoesNotAbort() throws Exception {
AtomicInt ai = new RecoverableContainer<atomicint>().enlist(new AtomicIntImpl());
AtomicAction tx = new AtomicAction();
ai.set(1);
tx.begin();
{
try {
ai.set(2);
throw new Exception();
} catch (Exception e) {
assertEquals(2, ai.get());
// the transaction should still be active
ai.set(3);
tx.commit();
}
}
assertEquals(3, ai.get());
}
</atomicint></pre>
<br />
<h2>
What's Next</h2>
That's all for this week. In the next instalment I will cover conflict detection and resolution, transaction granularity and concurrency control.</div>
Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-23835075454712712972018-06-28T06:17:00.000+01:002018-06-28T07:11:15.187+01:00Narayana Commit Markable Resource: a faultless LRCO for JDBC datasources<p>
CMR is neat Narayana feature enabling full XA transaction capability for one non-XA JDBC resource.
This gives you a way to engage a database resource to XA transaction even
the JDBC driver is not fully XA capable (or you just have a design restriction on it)
while transaction data consistency is kept.
</p>
<h2>Last resource commit optimization (aka. LRCO)</h2>
<p>
Maybe you will say "<i>adding one non-XA resource to a transaction is well-known LRCO optimization</i>".
And you are right. But just partially. The last resource commit optimization (abbreviated as LRCO)
provides a way to enlist and process one non-XA datasource to the global transaction managed by the transaction manager. But LRCO contains a pitfall. When the crash of the system
(or the connection) happens in particular point of the time,
<a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">during two-phase commit processing</a>,
it causes data inconsistency. Namely, the LRCO could be committed while the rest of the resources will be rolled-back.
</p>
<p>
Let's elaborate a bit on the LRCO failure. Let's say we have a JMS resource where we send a message to a message broker and non-XA JDBC datasource where we save information to the database.
<p>
<p>
<i>NOTE: The example refers to the Narayana two-phase commit implemenation.</i>
<br/><br/>
<ol>
<li>updating the database with <code>INSERT INTO</code> SQL command, enlisting LRCO resource under the transaction</li>
<li>sending a message to the JMS broker, enlisting the JMS resource to the transaction</li>
<li>Narayana starts the two phase commit processing</li>
<li><code>prepare</code> is called to JMS XA resource, the transaction log is stored
at the JMS broker side</li>
<li><code>prepare</code> phase for the LRCO means to call <code>commit</code> at the non-XA
datasource. That call makes the data changes visible to the outer world.</li>
<li>crash of the Narayana JVM occurs before the Narayana can preserve
information of commit to its transaction log store</li>
<li>after the Narayana restarts there is no notion about the existence of any
transaction thus the prepared JMS resource is rolled-back during transaction recovery</li>
</ol>
<p>
<i>Note:</i> roll-backing of the JMS resource is caused by <a href="http://narayana.io//docs/product/index.html#two-phase-variants">presumed abort strategy</a>
applied in the Narayana. If transaction manager does do not apply the presumed abort then
you end ideally not better than in the <a href="http://jbossts.blogspot.com/2011/03/heuristics-and-why-you-need-to-know.html">transaction heuristic state</a>.
</p>
</p>
<p>
The LRCO processing is about ordering the LRCO resource as the last
during the <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">transaction manager 2PC</a>
<code>prepare</code> phase.
At place where transaction normally calls <code>prepare</code> at <code>XAResource</code>s there is called
<code>commit</code> at the LRCO's underlaying non-XA resource.
<br/>
Then during the transaction manager <code>commit</code> phase there is called nothing for the LRCO.
</p>
<h2>Commit markable resource (aka. CMR)</h2>
<p>
The Commit Markable Resource, abbreviated as <code>CMR</code>, is an enhancement of the last resource commit optimization applicable on the JDBC resources.
The CMR approach achieves capabilities similar to XA by demanding special database table (normally named <code>xids</code>)
that is accessible for transaction manager to write and to read via the configured CMR datasource.
</p>
<p>
Let's demonstrate the CMR behavior at the example (reusing setup from the previous one).
<ol>
<li>updating the database with <code>INSERT INTO</code> SQL command, enlisting the CMR resource under the transaction</li>
<li>sending a message to the JMS broker, enlisting the JMS resource to the transaction</li>
<li>Narayana starts the two phase commit processing</li>
<li><code>prepare</code> on CMR saves information about prepare to the <code>xids</code> table</li>
<li><code>prepare</code> is called to JMS XA resource, the transaction log is stored at the JMS broker side</li>
<li><code>commit</code> on CMR means calling commit on underlaying non-XA datasource</li>
<li><code>commit</code> on JMS XA resource means commit on the XA JMS resource and thus the message being visible at the queue,
the proper transaction log is removed at the JMS broker side</li>
<li>Narayana two phase commit processing ends</li>
</ol>
</p>
<p>
From what you can see here the difference from the LRCO example is that the CMR
resource is not ordered as last in the resource processing but it's ordered
as the first one. The CMR prepare does not mean committing the work as in case of the LRCO
but it means saving information about that CMR is considered to be prepared into the database <code>xids</code> table.
<br/>
As the CMR is ordered as the first resource for processing it's taken as first during the commit phase too. The commit call then means to call <code>commit</code> at the underlying
database connection. The <code>xids</code> table is not cleaned at that phase
and it's normally responsibility of <code>CommitMarkableResourceRecordRecoveryModule</code>
to process the garbage collection of records in the <code>xids</code> table (see more below).
</p>
<p>
The main fact to understand is that CMR resource is considered as <i>fully prepared</i>
only after the <code>commit</code> is processed (meaning commit on the underlaying non-XA JDBC datasource).
Till that time the transaction is considered as <b>not</b> prepared and will be processed with rollback by the transaction recovery.
</p>
<p>
<i>NOTE:</i> the term <i>fully prepared</i> considers the standard XA two-phase commit
processing. If the transaction manager finishes with the <code>prepare</code> phase,
aka. prepare is called on all transaction participants, the transaction is counted
as prepared and <code>commit</code> is expected to be called on each participant.
</p>
<p>
It's important to note that the correct processing of failures in transactions which contain CMR resources
is responsibility of the special <a href="https://jbossts.blogspot.com/2018/01/narayana-periodic-recovery-of-xa.html">periodic recovery module</a>
<code>CommitMarkableResourceRecordRecoveryModule</code>.
It has to be configured as <b>the first</b> in the recovery module list as it needs to check
and eventually process all the XA resources belonging to the transaction which contains the CMR resource
(the recovery modules are processed in the order they were configured). You can check
<a href="https://github.com/wildfly/wildfly/blob/13.0.0.Final/transactions/src/main/java/org/jboss/as/txn/service/ArjunaRecoveryManagerService.java#L104">here how this is set up in WildFly</a>.
<br/>
The CMR recovery module knows about the existence of the CMR resource from the record saved in the <code>xids</code> table.
From that it's capable to pair all the resources belonging to the same transaction where CMR was involved.
</p>
<h4>xids: database table to save CMR processing data</h4>
<p>
As said Narayana needs a special database table (usually named <code>xids</code>)
to save information that CMR was prepared. You may wonder what is content of that table.
<br/>
The table consists of three columns.
<ul>
<li><i>xid</i> : id of the transaction branch belonging to the CMR resource</li>
<li><i>transactionManagerID</i> : id of transaction manager, this serves to distinguish more transaction managers (WildFly servers) working with the same database.
There is a strict rule that each transaction manager must be defined with unique transaction id
(<a href="https://wildscribe.github.io/WildFly/13.0/subsystem/transactions/index.html">see description of the node-identifer</a>).</li>
<li><i>actionuid</i> : global transaction id which unites all the resources belonging to the one particular transaction</li>
</ul>
</p>
<h4>LRCO failure case with CMR</h4>
<p>
In the example, we presented as problematic for LRCO, the container crashed just before prepare phase finished.
In such case, the CMR is not committed yet. The other transaction participants are then rolled-back
as the transaction was not <i>fully prepared</i>. The CMR brings the consistent rollback outcome for all the resources.
</p>
<h2>Commit markable resource configured in WildFly</h2>
<p>
We have sketched the principle of the CMR and now it's time to check
how to configure it for your application running at the <a href="http://wildfly.org">WildFly</a> application server.
<br/>
The configuration consists of three steps.
<ol>
<li>The JDBC datasource needs to be marked as <i>connectable</i></li>
<li>The database, the connectable datasource points to, has to be enriched with the <code>xids</code> table
where Narayana can saves the data about CMR processing</li>
<li>Transaction subsystem needs to be configured to be aware of the CMR capable resource</li>
</ol>
</p>
<p>
In our example, I use the H2 database as it's good for the showcase. You can find it in quickstart I prepared too. Check out the
<a href="https://github.com/jbosstm/quickstart/tree/master/wildfly/commit-markable-resource">
https://github.com/jbosstm/quickstart/tree/master/wildfly/commit-markable-resource</a>.
</p>
<h3>Mark JDBC datasource as connectable</h3>
<p>
You will mark the resource as <code>connectable</code> when you use attribute <code>connectable="true"</code>
in your datasource declaration in <code>standalone*.xml</code> configuration file.
When you use jboss cli for the app server configuration you will use commands
</p>
<pre><code class="bash">/subsystem=datasources/data-source=jdbc-cmr:write-attribute(name=connectable, value=true)
:reload
</code></pre>
<p>
The whole datasource configuration then looks like
</p>
<pre><code class="xml"><datasource jndi-name="java:jboss/datasources/jdbc-cmr" pool-name="jdbc-cmr-datasource"
enabled="true" use-java-context="true" connectable="true">
<connection-url>jdbc:h2:mem:cmrdatasource</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
</code></pre>
<p>
When datasource is marked as connectable then the IronJacamar (JCA layer of WildFly)
creates the datasource instance as implementing
<a href="https://github.com/ochaloup/jboss-transaction-spi/blob/master/src/main/java/org/jboss/tm/ConnectableResource.java"><code>org.jboss.tm.ConnectableResource</code></a>
(defined in the <a href="https://github.com/ochaloup/jboss-transaction-spi">jboss-transaction-spi project</a>).
This resource defines that the class provides method <code>getConnection() throws Throwable</code>.
That's how the transaction manager is capable to obtain the connection to the database
and works with the <code>xids</code> table inside it.
</p>
<h3>Xids database table creation</h3>
<p>
The database configured to be <code>connectable</code> has to ensure existence of the <code>xids</code>
before transaction manager starts. As described above the <code>xids</code>
allows to save the cruical information about the non-XA datasource during prepare.
The shape of the SQL command depends on the SQL syntax of the database you use.
The example of the
<a href="https://github.com/jbosstm/narayana/blob/5.8.2.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/CommitMarkableResourceRecord.java#L74">
table cleation commands is (see more commands under this link)</a>
</p>
<pre><code class="sql">-- Oracle
CREATE TABLE xids (
xid RAW(144), transactionManagerID VARCHAR(64), actionuid RAW(28)
);
CREATE UNIQUE INDEX index_xid ON xids (xid);
-- PostgreSQL
CREATE TABLE xids (
xid bytea, transactionManagerID varchar(64), actionuid bytea
);
CREATE UNIQUE INDEX index_xid ON xids (xid);
-- H2
CREATE TABLE xids (
xid VARBINARY(144), transactionManagerID VARCHAR(64), actionuid VARBINARY(28)
);
CREATE UNIQUE INDEX index_xid ON xids (xid);
</code></pre>
<p>
I addressed the need of the table definition in <a href="https://github.com/jbosstm/quickstart/tree/master/wildfly/commit-markable-resource">the CMR quickstart</a>
by adding the JPA schema generation create script which contains
<a href="https://github.com/jbosstm/quickstart/blob/master/wildfly/commit-markable-resource/src/main/resources/META-INF/persistence.xml#L44">the SQL to initialize the database</a>.
</p>
<h3>Transaction manager CMR configuration</h3>
<p>
The last part is to configure the CMR for the transaction subsystem.
The declaration puts the datasource under the list
<a href="https://github.com/jbosstm/narayana/blob/5.8.2.Final/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java#L104">JTAEnvironmentBean#commitMarkableResourceJNDINames</a>
which is then used in code of
<a href="https://github.com/jbosstm/narayana/blob/5.8.2.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/TransactionImple.java#L798">TransactionImple#createResource</a>.
<br/>
The xml element used in the transaction subsystem and the jboss cli commands look like
</p>
<pre><code class="xml"><commit-markable-resources>
<commit-markable-resource jndi-name="java:jboss/datasources/jdbc-cmr"/>
</commit-markable-resources>
</code></pre>
<pre><code class="bash">/subsystem=transactions/commit-markable-resource="java:jboss/datasources/jdbc-cmr":add()
:reload
</code></pre>
<h4>CMR configuration options</h4>
<p>
In addition to such simple CMR declaration, the CMR can be configured
with following parameters
</p>
<p>
<ul>
<li><b>jndi-name</b> : as it could be seen above the jndi-name is way to point
to the datasource which we mark as CMR ready</li>
<li><b>name</b> : defines the name of the table which is used for storing
the CMR state during prepare while used during recovery.
<br/>The default value (and we've reffered to it in this way above) is <code>xids</code></li>
<li><b>immediate-cleanup</b> : If configured to true then there is registered
<a href="https://github.com/jbosstm/narayana/blob/5.8.2.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/CommitMarkableResourceRecord.java#L191">a synchronization</a>
which removes proper value from the <code>xids</code>
table immediatelly after the transaction is committed.
<br/>
When synchronization is not set up then the clean-up of the <code>xids</code>
table is responsibility of the recovery by the code at
<a href="https://github.com/jbosstm/narayana/blob/5.8.2.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/CommitMarkableResourceRecordRecoveryModule.java#L76"><code>CommitMarkableResourceRecordRecoveryModule</code></a>.
It checks about finished xids and it removes those which are free for garbage collection.
<br/>The default value is <code>false</code> (using only recovery garbage collection).</li>
<li><b>batch-size</b> : This parameter influences the process of the garbage collection
(as described above).
The garbage collection takes finished xids and runs <code>DELETE</code>
SQL command. The <code>DELETE</code> contains the <code>WHERE xid in (...)</code> clause
with maximum of <code>batch-size</code> entries provided.
When there is still some finished xids left after deletion,
another SQL command is assembled with maximum number of <code>batch-size</code>
entries again.
<br/>The default value is <code>100</code>.</li>
</ul>
<br/>
The <code>commit-markable-resource</code> xml element configured with all the parameters looks like
</p>
<pre><code class="xml"><subsystem xmlns="urn:jboss:domain:transactions:4.0">
<core-environment>
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
<commit-markable-resources>
<commit-markable-resource jndi-name="java:jboss/datasources/jdbc-cmr">
<xid-location name="myxidstable" batch-size="10" immediate-cleanup="true"/>
</commit-markable-resource>
</commit-markable-resources>
</subsystem>
</code></pre>
<p>And the jboss cli commands for the same are</p>
<pre><code class="bash">/subsystem=transactions/commit-markable-resource="java:jboss/datasources/jdbc-cmr"\
:write-attribute(name=name, value=myxidstable)
/subsystem=transactions/commit-markable-resource="java:jboss/datasources/jdbc-cmr"\
:write-attribute(name=immediate-cleanup, value=true)
/subsystem=transactions/commit-markable-resource="java:jboss/datasources/jdbc-cmr"\
:write-attribute(name=batch-size, value=10)
:reload
</code></pre>
<p>
<i>NOTE:</i> the JBoss EAP documentation about the CMR resource configuration can be found
at section
<a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.1/html/development_guide/java_transaction_api_jta#about_the_lrco_optimization_for_single_phase_commit_1pc">
About the LRCO Optimization for Single-phase Commit (1PC)</a>
</p>
<h2>Conclusion</h2>
<p>
The article explained what is the Narayana Commit Markable resource (CMR),
it compared it with LRCO and presented its advantages. In the latter part of the article
you found how to configure the CMR resource in your application deployed at the <a href="http://wildfly.org/">WildFly application server</a>.
<br/>
If you like to run an application using the commit markable resource feature,
check our Narayana quickstart at <a href="https://github.com/jbosstm/quickstart/tree/master/wildfly/commit-markable-resource">
<b>https://github.com/jbosstm/quickstart/tree/master/wildfly/commit-markable-resource</b></a>.
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-41404632089314321572018-05-21T23:16:00.001+01:002018-06-28T07:13:28.566+01:00Narayana JDBC integration for Tomcat<p>
Narayana implements JTA specification in Java. It's flexible and easy to be integrated to any system
which desires transaction capabilities. As proof of the Narayana extensibility check our quickstarts like
<a href="https://github.com/jbosstm/quickstart/tree/master/spring/narayana-spring-boot">Spring Boot one</a>
or <a href="https://github.com/jbosstm/quickstart/tree/master/spring/camel-with-narayana-spring-boot">Camel one</a>.
<br/>
But this blogpost is different integration effort. It talks in details about Narayana integration with Apache Tomcat server.
</p>
<p>
If you do not care about details then just jump directly to the Narayana quickstarts in this area and use the code there for yourself.
<ul>
<li><a href="https://github.com/jbosstm/quickstart/tree/5.8.1.Final/dbcp2-and-tomcat">dbcp2-and-tomcat</a></li>
<li><a href="https://github.com/jbosstm/quickstart/tree/5.8.1.Final/transactionaldriver/transactionaldriver-and-tomcat">transactionaldriver-and-tomcat</a></li>
<li><a href="https://github.com/jbosstm/quickstart/tree/5.8.1.Final/jca-and-tomcat">jca-and-tomcat</a></li>
</ul>
<br/>
If you want more detailed understanding read further.<br/>
All the discussed abilities are considered as the state of Narayana 5.8.1.Final or later.
</p>
<h2>Narayana, database resources and JDBC interface</h2>
<p>
All the proclaimed Narayana capabilities to integrate with other systems come
from requirements for the system to conform with the <a href="https://github.com/javaee/jta-spec">JTA specification</a>.
JTA expects manageable resources which follows <a href="pubs.opengroup.org/onlinepubs/009680699/toc.pdf">XA specification</a> in particular.
For case of the database resources the underlaying API is defined by <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/">JDBC specification</a>.
JDBC assembled resources manageable by transaction manager under package <code>javax.sql</code>
<a href="https://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html">It defines interfaces</a> used for managing
XA capabilities. The probably most noticable is <a href="https://docs.oracle.com/javase/8/docs/api/javax/sql/XADataSource.html">XADataSource</a>
which serves as factory for <a href="https://docs.oracle.com/javase/8/docs/api/javax/sql/XAConnection.html">XAConnection</a>.
From there we can otain <a href="https://docs.oracle.com/javase/8/docs/api/javax/transaction/xa/XAResource.html">XAResource</a>.
The <code>XAResource</code> is interface that the transaction manager works with. The instance of it
participates in <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">the two phase commit</a>.
</p>
<p>
The workflow is to get or create the <code>XADataSource</code>, obtains <code>XAConnection</code>
and as next the <code>XAResource</code> which is enlisted to the global transaction (managed by a transaction manager).
Now we can call queries or statements through the <code>XAConnection</code>. When all the business work is finished the global transaction is commanded to commit which is propagated to call the commit on each enlisted <code>XAResource</code>s.
</p>
<p>
It's important to mention that developer is not expected to do all this
(getting xa resources, enlisting them to transaction manager…)
All this handling is responsibility of the "container" which could be <a href="http://wildfly.org">WildFly</a>,
<a href="https://spring.io/guides/gs/managing-transactions">Spring</a> or <a href="http://tomcat.apache.org/">Apache Tomcat</a> in our case.
<br/>
Normally the integration which ensures the database <code>XAResource</code> is enlisted
to the transaction is provided by some <i>pooling library</i>. By the term <i>pooling library</i>
we means code that manages a connection pool with capability
enlisting database resource to the transaction.
</p>
<p>
We can say at the high level that integration parts are
<ul>
<li>the Apache Tomcat container</li>
<li>Narayana library</li>
<li>jdbc pooling library</li>
</ul>
<br/>
In this article we will talk about <a href="https://github.com/jbosstm/narayana/tree/5.8.1.Final/ArjunaJTA/jdbc">Narayana JDBC transactional driver</a>,
<a href="https://github.com/apache/commons-dbcp">Apache Commons DBCP</a> and
<a href="https://github.com/ironjacamar/ironjacamar">IronJacamar</a>.
</p>
<h2>Narayana configuration with Tomcat</h2>
<p>
After the brief overview of integration requirements, let's elaborate on
common settings needed for any integration approach you choose.<br/>
Be aware that each library needs a little bit different configuration and especially IronJacamar is specific.
</p>
<h3>JDBC pooling libraries integration</h3>
<p>
Narayana provides integration code in maven module
<a href="https://github.com/jbosstm/narayana/tree/5.8.1.Final/tomcat/tomcat-jta"><code>tomcat-jta</code></a>.
That contains the glue code which integrates Narayana to the world of the Tomcat.
If you write an application you will need the following:
<ul>
<li>providing Narayana itself to the application classpath</li>
<li>providing Narayana <code>tomcat-jta</code> module to the application classpath</li>
<li>configure <code>WEB-INF/web.xml</code> with <code>NarayanaJtaServletContextListener</code>
which ensures the intialization of Narayana transaction manager</li>
<li>add <code>META-INF/context.xml</code> which setup Tomcat to start using
implementation of JTA interfaces provided by Narayana</li>
<li>configure database resources to be XA aware and cooperate with Narayana by setting
them up in the <code>META-INF/context.xml</code></li>
</ul>
<br/>
<i>NOTE:</i> if you expect to use the IronJacamar this requirements differs a bit!
</p>
<p>
If we take a look at the structure of the jar to be deployed we would get the picture
possibly similar to this one:
<pre>
├── META-INF
│ └── context.xml
└── WEB-INF
├── classes
│ ├── application…
│ └── jbossts-properties.xml
├── lib
│ ├── arjuna-5.8.1.Final.jar
│ ├── jboss-logging-3.2.1.Final.jar
│ ├── jboss-transaction-spi-7.6.0.Final.jar
│ ├── jta-5.8.1.Final.jar
│ ├── postgresql-9.0-801.jdbc4.jar
│ └── tomcat-jta-5.8.1.Final.jar
└── web.xml
</pre>
</p>
<p>
From this summary let's overview the configuration files one by one to see what's needed to be defined there.
</p>
<h3>Configuration files to be setup for the integration</h3>
<h4>WEB-INF/web.xml</h4>
<p>
<pre><code class="xml">
<web-app>
<listener>
<listener-class>org.jboss.narayana.tomcat.jta.NarayanaJtaServletContextListener</listener-class>
</listener>
</web-app>
</code></pre>
</p>
<p>
The <code>web.xml</code> needs to define the
<a href="https://github.com/jbosstm/narayana/blob/5.8.1.Final/tomcat/tomcat-jta/src/main/java/org/jboss/narayana/tomcat/jta/NarayanaJtaServletContextListener.java">NarayanaJtaServletContextListener</a>
to be loaded during context initialization to initialize the Narayana itself.
Narayana needs to get running, for example, reaper thread that ensures transaction timeouts checking or thread of recovery manager.
</p>
<h4>WEB-INF/clases/jbossts-properties.xml</h4>
<p>
This file is not compulsory.
The purpose is to configure the Narayana itself.<br/>
If you don't use your own configuration file then the default is in charge.
See more at blogpost
<a href="https://jbossts.blogspot.cz/2018/01/narayana-periodic-recovery-of-xa.html#configuration"> Narayana periodic recovery of XA transactions </a>
or consider settings done by the default descriptor
<a href="https://github.com/jbosstm/narayana/blob/5.8.1.Final/ArjunaJTS/narayana-jts-idlj/src/main/resources/jbossts-properties.xml">jbossts-properties.xml at narayana-jts-idlj</a>.
</p>
<h4>META-INF/context.xml</h4>
<p>
<pre><code class="xml">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Context antiJarLocking="true" antiResourceLocking="true">
<!-- Narayana resources -->
<Transaction factory="org.jboss.narayana.tomcat.jta.UserTransactionFactory"/>
<Resource factory="org.jboss.narayana.tomcat.jta.TransactionManagerFactory"
name="TransactionManager" type="javax.transaction.TransactionManager"/>
<Resource factory="org.jboss.narayana.tomcat.jta.TransactionSynchronizationRegistryFactory"
name="TransactionSynchronizationRegistry" type="javax.transaction.TransactionSynchronizationRegistry"/>
<Resource auth="Container" databaseName="test" description="Data Source"
factory="org.postgresql.xa.PGXADataSourceFactory" loginTimeout="0"
name="myDataSource" password="test" portNumber="5432" serverName="localhost"
type="org.postgresql.xa.PGXADataSource" user="test" username="test"
uniqueName="myDataSource" url="jdbc:postgresql://localhost:5432/test"/>
<Resource auth="Container" description="Transactional Data Source"
factory="org.jboss.narayana.tomcat.jta.TransactionalDataSourceFactory"
initialSize="10" jmxEnabled="true" logAbandoned="true" maxAge="30000"
maxIdle="16" maxTotal="4" maxWaitMillis="10000" minIdle="8"
name="transactionalDataSource" password="test" removeAbandoned="true"
removeAbandonedTimeout="60" testOnBorrow="true" transactionManager="TransactionManager"
type="javax.sql.XADataSource" uniqueName="transactionalDataSource"
username="test" validationQuery="select 1" xaDataSource="myDataSource"/>
</Context>
</code></pre>
</p>
<p>
I divide explanation this file into two parts. First are the generic settings -
those needed for transaction manager integration (top part of the <code>context.xml</code>).
The second part is on resource declaration that defines linking to the JDBC pooling library.
</p>
<h5>Transaction manager integration settings</h5>
<p>
We define implementation classes for the <a href="https://github.com/eclipse-ee4j/jta-api">JTA api</a> here.
The implementation is provided by Narayana transaction manager.
Those are lines of <code>UserTransactionFactory</code> and
resources of <code>TransactionManager</code> and <code>TransactionSynchronizationRegistry</code>
in the <code>context.xml</code> file.<br/>
</p>
<h5>JDBC pooling library settings</h5>
<p>
We aim to define database resources that can be used in the application.
That's how you <a href="https://github.com/jbosstm/quickstart/blob/master/dbcp2-and-tomcat/src/main/java/io/narayana/StringDao.java#L119">get the connection</a>
typically with code <code class="java">DataSource ds = InitialContext.doLookup("java:comp/env/transactionalDataSource")</code>,
and eventually <a href="https://github.com/jbosstm/quickstart/blob/master/dbcp2-and-tomcat/src/main/java/io/narayana/StringDao.java#L81">execute a sql statement</a>.
<br/>
We define a PostgreSQL datasource with information how to create a new XA connection
(we provide the host and port, credentials etc.) in the example.<br/>
The second resource is definition of jdbc pooling library to utilize the PostgreSQL one
and to provide the XA capabilities. It roughtly means putting the PostgreSQL connection
to the managed pool and enlisting the work under an active transaction.
<br/>
Thus we have got two resources defined here. One is non-managed
(the PosgreSQL one) and the second manages the first one to provide
the ease work with the resources. For the developer is the most important to know
he needs to use the managed one in his application, namely the <code>transactionalDataSource</code>
from our example.
</p>
<h5>A bit about datasource configuration of Apache Tomcat context.xml</h5>
<p>
Let's take a side step at this place.
Before we will talk in details about supported pooling libraries
let's check a little bit more about the configuration of the <code>Resource</code>
from perspective of XA connection in the <code>context.xml</code>.
</p>
<p>
Looking at the <code>Resource</code> definition there are highlighted parts which are
interesting for us
<pre>
<Resource auth="Container" <span style="color:rgb(255, 150, 200)">databaseName="test"</span> description="Data Source"
<span style="color:rgb(255, 150, 200)">factory="org.postgresql.xa.PGXADataSourceFactory"</span>
loginTimeout="0" <span style="color:rgb(255, 150, 200)">name="myDataSource"</span> <span style="color:rgb(255, 150, 200)">password="test"</span> <span style="color:rgb(255, 150, 200)">portNumber="5432"</span> <span style="color:rgb(255, 150, 200)">serverName="localhost"</span>
<span style="color:rgb(255, 150, 200)">type="org.postgresql.xa.PGXADataSource"</span> uniqueName="myDataSource"
url="jdbc:postgresql://localhost:5432/test" <span style="color:rgb(255, 150, 200)">user="test"</span> username="test"/>
</pre>
</p>
<p>
<ul>
<dl>
<dt><code>name</code></dt>
<dd>defines the name the resource is bound at the container and we can use
the jndi lookup to find it by that name in application</dd>
<dt><code>factory</code></dt>
<dd>defines what type we will get as the final created <code>Object</code>.
The factory which we declares here is class which implements interface
<a href="https://docs.oracle.com/javase/8/docs/api/javax/naming/spi/ObjectFactory.html">ObjectFactory</a>
and from the provided properties it construct an object.<br/>
If we would not define any <code>factory</code> element in the definition then
the Tomcat class <a href="https://github.com/apache/tomcat/blob/trunk/java/org/apache/naming/factory/ResourceFactory.java#L42">ResourceFactory</a>
is used (see <a href="https://github.com/apache/tomcat/blob/trunk/java/org/apache/naming/factory/Constants.java#L26">default factory constants</a>).
The <code>ResourceFactory</code> will pass the call to the
<a href="https://github.com/apache/tomcat/blob/trunk/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java">BasicDataSourceFactory</a>
of the dbcp2 library. Here we can see the importantce of the <code>type</code> xml parameter which defines what is the object type we want to
obtain and the factory normally checks if it's able to provide such (by
<a href="https://github.com/apache/tomcat/blob/trunk/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java#L251">string equals check</a> usually).<br/>
The next step is generation of the object itself where the factory takes each
of the <a href="https://github.com/apache/tomcat/blob/trunk/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java#L365">properties and tries to applied</a> them.
<br/>
In our case we use the <a href="https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/xa/PGXADataSourceFactory.java">PGXADataSourceFactory</a>
which utilizes <a href="https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java#L1212">some of the properties to create the <code>XADataSource</code></a>.
</dd>
<dt><code>serverName</code>, <code>portNumber</code>, <code>databaseName</code>, <code>user</code>, <code>password</code></dt>
<dd>are properties used by the <code>object factory</code> class to get connection from the database
<br/>
Knowing the name of the properties for the particular <code>ObjectFactory</code> is possibly the most important
when you need to configure your datasource. Here you need to check <code>setters</code> of the factory implementation.
<br/>
In case of the <code>PGXADataSourceFactory</code> we need to
go through the inheritance hierarchy to find the properties are saved at
<a href="https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java">BaseDataSource</a>.
For our case for the relevant properties are <code>user name</code> and <code>password</code>. From the <code>BaseDataSource</code>
we can see the setter for the user name is <a href="https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java#L190">setUser</a>
thus the property name we look for is <code>user</code>.
</dd>
</dl>
</ul>
</p>
<p>
After this side step let's take a look at the setup of the <code>Resource</code>s
in respect of the used pooling library.
</p>
<br/><br/>
<h3>Apache Commons DBCP2 library</h3>
<p><b>Quickstart:</b> <a href="https://github.com/jbosstm/quickstart/tree/master/dbcp2-and-tomcat">https://github.com/jbosstm/quickstart/tree/master/dbcp2-and-tomcat</a>
</p>
<p>
The best integration comes probably with Apache Common DBCP2 as the library itself is part of the Tomcat distribution
(the Tomcat code base uses <a href="https://github.com/apache/tomcat/tree/trunk/java/org/apache/tomcat/dbcp/dbcp2">fork of the project</a>).
The XA integration is provided in Apache Tomcat version 9.0.7 and later. There is added dbcp2 package
<a href="https://github.com/apache/tomcat/tree/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed">managed</a>
which knows how to enlist a resource to XA transaction.
</p>
<p>
The integration is similar to what we discussed in case of the JDBC transactional driver.
You need to have configured two resources in <code>context.xml</code>. One is
the database datasource (<a href="#contextxmldatasource">see above</a>) and other
is wrapper providing XA capabilities.
</p>
<pre><code style="xml">
<Resource name="transactionalDataSource" uniqueName="transactionalDataSource"
auth="Container" type="javax.sql.XADataSource"
transactionManager="TransactionManager" xaDataSource="h2DataSource"
factory="org.jboss.narayana.tomcat.jta.TransactionalDataSourceFactory"/>
</code></pre>
<p>
The integration is here done over the use of the specific <code>factory</code>
which directly depends on classes from Apache Tomcat <code>org.apache.tomcat.dbcp.dbcp2</code> package.
The factory ensures the resource being enlisted to the recovery manager as well.<br/>
The nice feature is that you can use all the DBCP2 configuration parameters for pooling
as you would used when <code>BasicDataSource</code> is configured. See the configuration options
and the their meaning at the <a href="https://commons.apache.org/proper/commons-dbcp/configuration.html">Apache Commons documentation</a>.
</p>
<p>
<b>Summary:</b>
<ul>
<li>Already packed in the <code>Apache Tomcat</code> distribution from version 9.0.7</li>
<li>Configure two resources in <code>context.xml</code>. One is the database datasource,
the second is wrapper providing XA capabilities with use of the <code>dbcp2</code> pooling capabilities
integrated with <code>TransactionalDataSourceFactory</code>.</li>
</ul>
</p>
<table border="1"><tr><td>
<p>
<i>NOTE:</i> if you consider checking <a href="https://issues.jboss.org/browse/JBTM-3032">the pool status over JMX</a> calls then DBCP2
comes with <code>BasicDataSourceMXBean</code> which exposes some information about the pool. You need to provide <code>jmxName</code>
in your <code>context.xml</code>.
</p>
<pre><code style="xml">
<Resource name="transactionalDataSource" uniqueName="transactionalDataSource"
auth="Container" type="javax.sql.XADataSource"
transactionManager="TransactionManager" xaDataSource="h2DataSource"
jmxEnabled="true" jmxName="org.apache.commons.dbcp2:name=transactionalDataSource"
factory="org.jboss.narayana.tomcat.jta.TransactionalDataSourceFactory"/>
</code></pre>
</td></tr></table>
<br/><br/>
<h3>Narayana jdbc transactional driver</h3>
<p><b>Quickstart:</b> <a href="https://github.com/jbosstm/quickstart/tree/master/transactionaldriver/transactionaldriver-and-tomcat">https://github.com/jbosstm/quickstart/tree/master/transactionaldriver/transactionaldriver-and-tomcat</a></p>
<p>With this we will get back to other two recent articles about
<a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html">jdbc transactional driver</a>
and <a href="https://jbossts.blogspot.cz/2018/01/recovery-of-narayana-jdbc-transactional.html">recovery of the transactional driver</a>.<br/>
The big advantage of jdbc transactional driver is its tight integration with Narayana.
It's the dependecy of the <a href="https://github.com/jbosstm/narayana/tree/master/tomcat/tomcat-jta">Narayana <code>tomcat-jta</code></a>
module which contains all the integration code needed for Narayana working in Tomcat. So if you take the <code>tomcat-jta-5.8.1.Final</code>
you have packed the Narayna integration code and jdbc driver in out-of-the-box working bundle.
</p>
<h4>Configuration actions</h4>
<p>
Here we will define two resources in the <code>context.xml</code> file.
The first one is <a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/transactionaldriver/transactionaldriver-and-tomcat/src/main/webapp/META-INF/context.xml#L11">the database one</a>.
</p>
<a id="contextxmldatasource" name="contextxmldatasource"></a>
<pre><code style="xml">
<Resource name="h2DataSource" uniqueName="h2Datasource" auth="Container"
type="org.h2.jdbcx.JdbcDataSource" username="sa" user="sa" password="sa"
url="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" description="H2 Data Source"
loginTimeout="0" factory="org.h2.jdbcx.JdbcDataSourceFactory"/>
</code></pre>
<p>
The database one defines data needed for preparation of datasource and creation of the connection.
The datasource is not XA aware. We need to add one more layer on top which is transactional JDBC driver here.
<a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/transactionaldriver/transactionaldriver-and-tomcat/src/main/webapp/META-INF/context.xml#L14">It wraps the datasource connection</a>
within XA capabilities.
</p>
<pre><code style="xml">
<Resource name="transactionalDataSource" uniqueName="transactionalDataSource"
auth="Container" type="javax.sql.DataSource" username="sa" password="sa"
driverClassName="com.arjuna.ats.jdbc.TransactionalDriver"
url="jdbc:arjuna:java:comp/env/h2DataSource" description="Transactional Driver Datasource"
connectionProperties="POOL_CONNECTIONS=false"/>
</code></pre>
<p>
As we do not define the element <code>factory</code> then the default one is used
which is <code>org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory</code>.
Unfortunately, this is fine up to the time you need to process some more sophisticated pooling strategies. In this aspect the transactional driver does not play well with the default factory and some further integration work would be needed.
</p>
<p>
This configuration is nice for having <code>transactionalDataSource</code> available for the
transactional work. Unfortunately, it's not all that you need to do. You miss here configuration of recovery. You need to tell the recovery manager what is the resource to care of.
You can setup this in <code>jbossts-properties.xml</code> or maybe easier way to add it
to <a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/transactionaldriver/transactionaldriver-and-tomcat/run.sh#L10">environment variables of the starting Tomcat</a>,
for example by adding the setup under script <code>$CATALINA_HOME/bin/setenv.sh</code><br/>
You define it with property <a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java#L66">com.arjuna.ats.jta.recovery.XAResourceRecovery</a>.
</p>
<pre><code style="bash">
-Dcom.arjuna.ats.jta.recovery.XAResourceRecovery1=com.arjuna.ats.internal.jdbc.recovery.BasicXARecovery;abs://$(pwd)/src/main/resources/h2recoveryproperties.xml
</code></pre>
<p>
You can define whatever number of the resources you need the recovery is aware of.
It's done by adding more <code>numbers</code> at the end of the property name (we use <code>1</code> in the example above).
The value of the property is the class implementing <code>com.arjuna.ats.jta.recovery.XAResourceRecovery</code>.
All the properties provided to the particular implementation is concatenated after the <code>;</code> character.
In our example it's path to the <code>xml descriptor h2recoveryproperties.xml</code>.<br/>
When transactional driver is used then you need to declare<code>BasicXARecovery</code> as recovery
implementation class and this class needs
<a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/transactionaldriver/transactionaldriver-and-tomcat/src/main/resources/h2recoveryproperties.xml">connection properties</a>
to be declared in the xml descriptor.
</p>
<pre><code style="xml">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="DB_1_DatabaseUser">sa</entry>
<entry key="DB_1_DatabasePassword">sa</entry>
<entry key="DB_1_DatabaseDynamicClass"></entry>
<entry key="DB_1_DatabaseURL">java:comp/env/h2DataSource</entry>
</properties>
</code></pre>
<p>
Note: there is option not defining the two resources under <code>context.xml</code>
and use the env property for recovery enlistment. All the configuration
properties are then involved in one <code>properties</code> file and
<a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html">transactional driver dynamic class</a> is used.
If interested the working example is at
<a href="https://github.com/ochaloup/quickstart-jbosstm/tree/transactional-driver-and-tomcat-dynamic-class/transactionaldriver/transactionaldriver-and-tomcat">ochaloup/quickstart-jbosstm/tree/transactional-driver-and-tomcat-dynamic-class</a>.
</p>
<p>
<b>Summary:</b>
<ul>
<li>Already packed in the <code>tomcat-jta</code> artifact</li>
<li>Configure two resources in <code>context.xml</code>. One is database datasource,
the second is transactional datasource wrapped by transactional driver.</li>
<li>Need to configure recovery with env variable setup <code>com.arjuna.ats.jta.recovery.XAResourceRecovery</code>
while providing xml descriptor with connection parameters</li>
</ul>
</p>
<br/><br/>
<h3>IronJacamar</h3>
<p><b>Quickstart:</b> <a href="https://github.com/jbosstm/quickstart/tree/master/jca-and-tomcat">https://github.com/jbosstm/quickstart/tree/master/jca-and-tomcat</a>
</p>
<p>
The settings of IronJacamar integration differs pretty much from what we've seen so far.
The IronJacamar implements whole JCA specification and it's pretty different beast
(not <i>just</i> a jdbc pooling library).
</p>
<p>
The whole handling and integration is passed to IronJacamar itself.<br/>
You don't use <code>tomcat-jta</code> module at all.<br/>
You need to configure all aspects in the IronJacamar <code>xml descriptors</code>.
Aspects like datasource definition, transaction configuration, pooling definition, up to the jndi binding.
</p>
<p>
The standalone IronJacamar is needed to be started with command <code>org.jboss.jca.embedded.EmbeddedFactory.create().startup()</code>
where you <a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/jca-and-tomcat/src/test/java/org/jboss/narayana/quickstart/jca/common/AbstractTest.java#L51">defines the descriptors to be used</a>.
You can configure it in <code>web.xml</code> as
<a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/jca-and-tomcat/src/main/java/org/jboss/narayana/quickstart/jca/listener/ServletContextListenerImpl.java"><code>ServletContextListener</code></a>.
</p>
<p>
What are descriptors to be defined:
<ul>
<li><a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/jca-and-tomcat/src/main/resources/jdbc-xa.rar">jdbc-xa.rar</a>
which is resource adapter provided by IronJacamar itself. It needs to be part of the deployment. It's capable to process <code>ds</code> files.
</li>
<li><a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/jca-and-tomcat/src/main/resources/postgres-xa-ds.xml">ds.xml</a>
which defines connecion properties and jndi name binding
</li>
<li><a href="https://github.com/jbosstm/quickstart/blob/5.8.1.Final/jca-and-tomcat/src/main/resources/transaction.xml">transaction.xml</a>
which configures transaction manager instead of use of the <code>jbossts-properties.xml</code>.
</li>
</ul>
Check more configuration in <a href="http://www.ironjacamar.org/doc/userguide/1.2/en-US/html_single/index.html">IronJacamar documentation</a>.
</p>
<p>
<b>Summary:</b>
IronJacamar is started as embedded system and process all the handling on its own.
Developer needs to provide xml descriptor to set up.
</p>
<h2>Summary</h2>
<p>
This article provides the details about configuration of the Narayana when used in Apache Tomcat container. We've seen the three possible libraries to get the integration
working - the Narayana JDBC transactional driver, Apache DBCP2 library
and IronJacamar JCA implementation.<br/>
On top of it, the article contains many details about Narayana and Tomcat resource configuration.
</p>
<p>
If you hesitate what alternative is the best fit for your project then this table can help you
<table border="1" style="border-collapse: collapse; width: 100%; border: 1px solid #dddddd; text-align: left; padding: 8px;">
<tr style="background-color: #dddddd;">
<th width="180">JDBC integration library</th>
<th>When to use</th>
</tr>
<tr>
<td>Apache DBCP2</td>
<td>It's the recommended option when you want to obtain Narayana transaction handling in the Apache Tomcat
Integration is done in the Narayana resource factory which ensures easily setting up the
datasource and recovery in the one step.
</td>
</tr>
<tr>
<td>Narayana transactional jdbc driver</td>
<td>Is good fit when you want to have all parts integrated and covered by Narayana project.
It provides lightweight JDBC pooling layer that could be nice for small projects.
Integration requires a little bit more hand working.
</td>
</tr>
<tr>
<td>IronJacamar</td>
<td>To be used when you need whole JCA functionality running in Apache Tomcat.
The benefit of this solution is the battle tested integration of Narayana and IronJacamar
as they are delivered as one pack in the WildFly application server.
</td>
</tr>
</table>
</p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-65492935042746701302018-01-11T17:02:00.002+00:002021-07-29T08:41:02.975+01:00Narayana periodic recovery of XA transactions<p>
Let's talk about the transaction recovery with details specific to Narayana.<br/>
This blog post is related to JTA transactions. If you configure recovery for JTS,
still you can find a relevant information here but then you will need to consult
<a href="http://narayana.io/docs/product/index.html#d0e1281"> the Narayana documentation</a>.
</p>
<h2>What is the transaction recovery</h2>
<p>
The transaction recovery is process needed when an active transaction fails
for some reason. It could be a crash of process of the transaction manager (JVM)
or connection to the resource (database)could fail or any other reason for failure.<br />
The failure of the transaction could happen at various points of the transaction
lifetime and the point define the state which the in-progress transaction was left at.
The state could be just an in-memory state which is left behind and transaction
manager relies on the resource transaction timeout to release it. But it could
the transaction state after prepare was called (by successful prepare call
the 2PC transaction confirms that is capable to finish transaction and more of what it promises
to finish the transaction with <code>commit</code>).
There has to be a process which finishes such transaction remainders. And that process is the transaction recovery.<br />
Let's review three variants of failures which serves three different transaction states.
Their results and needs of termination will guide us through the work of the transaction recovery process.
</p>
<p>
Transaction manager runs a global transaction which includes several
transaction branches (when using term from <a href="http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf">XA specification</a>).
In our <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">article about 2PC</a> we used (not precisely) term
<a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC#resource-located-transaction">resource-located transaction</a>
instead of the transaction branch. <br />
Let's say we have a global transaction containing data insertion to a database
plus sending a message to a message broker queue.<br />
We will examine the crash of transaction manager (the JVM process)
where each point represents one of the three example cases. The examples show the
timeline of actions and differ in time when the crash happens.
</p>
<ol>
<li><a id="point-one" name="point-one"></a>
The global transaction was started and insertion to database happened, now JVM crashes.
(no message was sent to queue). In this situation, all the transaction metadata
is saved only in the memory. After JVM is restarted the transaction manager has no notion
of existence of the global transaction in time before.<br />
But the insertion to the database already happened and the database has some work in progress
already. But there was no promise by prepare call to end with commit and everything
was stored only as an in-memory state thus transaction manager relies on the database
to abort the work itself. Normally it happens when transaction timeout expires.
</li>
<li><a id="point-two" name="point-two"></a>
The global transaction was started, data was inserted into the database and message was
sent to the queue. The global transaction is asking to commit. The two-phase commit begins –
the <code>prepare</code> is called on the database
(<a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC#resource-located-transaction">resource-located transaction</a>).
Now the transaction manager (the JVM) crashes.
If an interleaving data manipulation would be permitted then the <code>2PC commit</code>
would fail. But calling of <code>prepare</code> means the promise of the successful end.
Thus the call of prepare causes locks to be taken to prevent other transactions to interleave.<br />
When transaction manager is restarted but again no notion
of the transaction could be found as all the in-memory state was cleared. And there was nothing
to be saved in the Narayana transaction log so far.<br />
But the database transaction is in the prepared state and with locks. On top of it, the transaction
in the prepared state can't be rolled-back by transaction timeout and needs to wait
for some other party to finish it.
</li>
<li><a id="point-three" name="point-three"></a>
The global transaction was started, data inserted into the database and message was
sent to the queue. The transaction was asked to commit. The two-phase commit
begins – the <code>prepare</code> is called on the database and on the message queue too.
A record success of the prepare phase is saved to the Narayana transaction log too.
Now the transaction manager (JVM) crashes.<br />
After the transaction manager is restarted there is no in-memory state
but we can observe the record in the Narayana transaction log and that database
and the JMS queue resource-located transactions are in the prepared state with locks.
</li>
</ol>
<p>
In the <a href="#point-three">later</a> cases the transaction state survived the JVM crash
- once only at the side of locked records of a database, in other cases, a record is present in transaction log too.
In <a href="#point-one">the first case</a> only in memory transaction representation was used
where transaction manager is not responsible to finish it.
<br />
The work of finishing the unfinished transactions belongs to the <code>recovery manager</code>.
The purpose of the recovery manager is to periodically check the state of the Narayana transaction log
and resource transaction logs (unfinished <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC">resource-located transactions</a>
– it runs the JTA API <a href="https://docs.oracle.com/javaee/7/api/javax/transaction/xa/XAResource.html#recover-int-">call of XAResource.recover()</a>.<br />
If an in-doubt transaction is found
the recovery manager either roll it back - <a href="#point-two">for example in the second case</a>,
or commit it as the whole prepare phase was originally finished with success, see <a href="#point-three">the third case</a>.
</p>
<h2>Narayana periodic recovery in details</h2>
The periodic recovery is the configurable process. That brings flexibility of the usage
but made necessary to use proper settings if you want to run it.<br />
We recommend checking <a href="http://narayana.io//docs/product/index.html#d0e823">
the Narayana documenation, the chapter Failure Recovery</a>.
<br />
The recovery runs periodicity (by default each two minutes) - the period could be changed
by setting system property
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L45">RecoveryEnvironmentBean.periodicRecoveryPeriod</a>).
When launched it iterates over all registered recovery modules (see Narayana codebase
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/recovery/RecoveryModule.java">com.arjuna.ats.arjuna.recovery.RecoveryModule</a>)
and it runs the following sequence: calling the method <code>periodicWorkFirstPass</code> on all recovery modules, waiting time defined by
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L46">RecoveryEnvironmentBean.recoveryBackoffPeriod</a>,
calling the method <code>RecoveryEnvironmentBean.recoveryBackoffPeriod</code> on all recovery modules.
<br />
When you want to run standard JTA XA transactions (JTS differs, you can check the
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTS/narayana-jts-idlj/src/main/resources/jbossts-properties.xml">config example in the Narayana code base</a>)
then you needs to configure the <a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java">XARecoveryModule</a>
for the usage. The XARecoveryModule then brings to the play need of configuring
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceOrphanFilter.java">XAResourceOrphanFilter</a>s
which manage finishing in-doubt transactions when available only at the resource side (<a href="#point-two">the second case represents such scenario</a>).
<br /><br />
<h3>
Narayana periodic recovery configuration</h3>
<a id="configuration" name="configuration"></a>
You may ask how all this is configured, right?<br />
The Narayana configuration is held in "beans". The "beans" contains properties which
are retrieved by getter method calls all over the Narayana code. So configuration of the Narayana
behaviour means redefining values of the demanded bean properties.<br />
Let's check what are the beans relevant for setting the transaction management
and recovery for XA transactions. We will use the <a href="https://github.com/jbosstm/quickstart/tree/master/transactionaldriver/transactionaldriver-standalone">jdbc transactional driver quickstart</a> as an example.
<br />
The releavant beans are following
<br />
<ul>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoreEnvironmentBean.java">CoreEnvironmentBean</a></li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java">CoordinatorEnvironmentBean</a></li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java">JTAEnvironmentBean</a></li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java">RecoveryEnvironmentBean</a></li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/jdbc/common/JDBCEnvironmentBean.java">JDBCEnvironmentBean</a></li>
</ul>
<br />
To configure the values of the properties you need to define it one of the following ways
<br />
<ul>
<li> via system property – see example
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/pom.xml#L82">in the quickstart <code>pom.xml</code></a><br />.
We can see that the property is passed at the JVM argument line.
</li>
<li>via use of the descriptor file <code>jbossts-properties.xml</code>.<br />
This is usually the main source of configuration in the standalone applications using Narayana.
You can see the example
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml">jbossts-properties.xml</a>
and observe that as the standalone application is not the exception.<br />
The descriptor has to be at the classpath for the Narayana will be able to access it.
</li>
<li>
via call of bean setter methods.<br />
This is the programatic approach and is normally used mainly in managed environment
as they are application servers as <a href="http://wildfly.org/">WildFly</a> is
(WildFly configures with <a href="https://docs.wildfly.org/24/wildscribe/subsystem/transactions/index.html">jboss-cli</a>).
</li>
</ul>
<br />
<ul>
<li>The usage of the system property has precedence over use of the descriptor <code>jbossts-properties.xml</code>.</li>
<li>The usage of the programatic call of the setter method has precedence over use of system properties.</li>
</ul>
<p>
The default settings for the used <code>narayana-idlj-jts.jar</code> artifact can be seen at
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTS/narayana-jts-idlj/src/main/resources/jbossts-properties.xml">https://github.com/jbosstm/narayana/blob/master/ArjunaJTS/narayana-jts-idlj/src/main/resources/jbossts-properties.xml</a>. Those are (with combination of settings inside of particular beans) default values used when you don't have any properties file defined.<br/>
For more details on configuration check <a href="http://narayana.io//docs/product/index.html#d0e3473">the Narayana.io documentation</a> (section <i>Development Guide -> Configuration options</i>).
</p>
<br />
If you want to use the programatic approach and call the bean setters you need to
gain the bean instance first. That is normally done by calling a static method
of <code>PropertyManager</code>. There are various of them
depending what you want to configure.<br />
The relevant for us are:
<br />
<ul>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/arjPropertyManager.java">
arjPropertyManager</a> for <code>CoreEnvironmentBean</code> etc.
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/recoveryPropertyManager.java">
recoveryPropertyManager</a> for <code>RecoveryEnvironmentBean</code>
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/jdbc/common/jdbcPropertyManager.java">
jdbcPropertyManager</a> for <code>JDBCEnvironementBean</code>
</li>
</ul>
<p>
We will examine the programmatic approach at the example of the jdbc transactional driver quickstart <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/recovery/RecoverySetupUtil.java">inside of the recovery utility class</a> where property controlling values of
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml#L100">XAResourceRecovery</a>
is reset <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/recovery/RecoverySetupUtil.java#L83">in the code</a>.
<br />
If you search to understand what should be the exact name of the system property or entry in <code>jbossts-properties.xml</code>
the rule of thumb is to take the short class name of the bean, add the <code>dot</code> and the name of the property at the end.<br />
For example let's say you want to redefine time period for
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml#L152">the periodic recovery cycle</a>.
Then you need to visit the <a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L45">RecoveryEnvironmentBean</a>,
find the name of the variable – which is <code>periodicRecoveryPeriod</code>. By using the rule of thumb
will use the name <code>RecoveryEnvironmentBean.periodicRecoveryPeriod</code> for redefinition of the
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/internal/arjuna/recovery/PeriodicRecovery.java#L943">default 2 minutes value</a>.<br />
Some bean uses annotations <a href="https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/RecoveryEnvironmentBean.java#L42"><code>@PropertyPrefix</code></a>
which offers other way of naming for the property for settings it up. In case of the <code>periodicRecoveryPeriod</code>
we can use system property with name <code>com.arjuna.ats.arjuna.recovery.periodicRecoveryPeriod</code> to reset it in the same way.
</p>
<i>Note:</i> an interesting link could be the settings for the integration with Tomcat
which useses programatic approach, see
<a href="https://github.com/jbosstm/narayana/blob/master/tomcat/tomcat-jta/src/main/java/org/jboss/narayana/tomcat/jta/NarayanaJtaServletContextListener.java#L91">NarayanaJtaServletContextListener</a>.
<br /><br />
<h2>Thinking about XA recovery</h2>
<p>
I hope you have a better picture of recovery setup and how that works now.
<br />
The <code>XARecoveryModule</code> has the responsibility for handling recovery of 2PC XA transactions.
The module is responsible for committing unfinished transactions and for handling orphans
by running registered <code>XAResourceOrphanFilter</code>.<br />
<br />
As you could see we configured two <code>RecoveryModule</code>s – <code>XARecoveryModule</code>
and <code>AtomicActionRecoveryModule</code>
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml">in the jbossts-properties.xml descriptor</a>.<br />
The <code>AtomicActionRecoveryModule</code> is responsible
for loading resource from object store and if it is serializable and as the whole saved
in the Narayana transaction log then it could be deserialized and used immediately during recovery.<br />
This is not the case often. When the <code>XAResource</code> is not serializable (which is hard to achieve
for example for database where we need to have
<a href="https://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html">a connection</a> to do any work)
the Narayana offers <i>resource initiated</i> recovery. That requires a class (a code and a settings)
that could provide <code>XAResources</code> for the recovery purposes. For getting the resource
we need a connection (to database, to jms broker...).
The <code>XARecoveryModule</code> uses objects of two interfaces to get such information (to get the <code>XAResource</code>s for recovery).<br />
Those interfaces are
</p>
<ul>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceRecoveryHelper.java">
XAResourceRecoveryHelper</a>
</li>
<li><a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceRecovery.java">
XAResourceRecovery</a>
</li>
</ul>
<p>
Both interfaces then contain method to retrieve the resources (<code>XAResourceRecoveryHelper.getXAResources()</code>,<code>XAResourceRecovery.getXAResource()</code>).
The <code>XARecoveryModule</code> then ask all the received
<code>XAResources</code> to find in-doubt transactions (by calling <code>XAResource.recovery()</code>)
(aka. <a href="https://developer.jboss.org/wiki/TwoPhaseCommit2PC#resource-located-transaction">resource located transactions</a>).<br />
The found in-doubt transactions are then paired with transactions in Narayana transaction log store.
If the match is found the <code>XAResource.commit()</code> could be called.<br />
Maybe you wonder what both interfaces are mostly the same – which kind of true – but the use differs.
The <code>XAResourceRecoveryHelper</code> is designed (and only available) to be used
in programatic way. For adding the helper amogst other ones you need to call
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java#L920">
XARecoveryModule.addXAResourceRecoveryHelper()</a>.
You can even deregister the helper by method call <code>XARecoveryModule.removeXAResourceRecoveryHelper</code>.<br />
The <code>XAResourceRecovery</code> is configured not directly in the code but via property
<code>com.arjuna.ats.jta.recovery.XAResourceRecovery</code>. This is not viable for dynamic changes
as in normal circumstances it's not possible to reset it – even when you try to change the values by call of
<code>JTAEnvironmentBean.setXaResourceRecoveryClassNames()</code>.
</p>
<h2>Running the recovery manager</h2>
<p>
We have explained how to configure the recovery properties but we haven't pointed down
one important fact – in the standalone application there is no automatic launch
of the recovery manager. You need manually to start it.<br />
A good point is that's quite easy (if you don't use ORB) and it's fine
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/recovery/RecoverySetupUtil.java#L64">to call just</a>
<br/>
<pre><code class="java">
RecoveryManager manager = RecoveryManager.manager();
manager.initialize()
</code></pre>
This runs an indirect recovery manager (<code>RecoveryManager.INDIRECT_MANAGEMENT</code>) which spawns
a thread which runs periodically the recovery process. If you feel that you need to run the periodic
recovery in times you want (periodic timeout value is then not used) you can use direct management
and call to run it manually
<pre><code class="java">
RecoveryManager manager = RecoveryManager.manager(RecoveryManager.DIRECT_MANAGEMENT);
manager.initialize();
manager.scan();
</code></pre>
For stopping the recovery manager to work use the <code>terminate</code> call.
<pre><code class="java">
manager.terminate();
</code></pre>
</p>
<h2>Summary</h2>
<p>
This blog post tried to introduce process of transaction recovery in Narayana.<br/>
The goal was to present settings necessary to be set for the recovery would work in an expected way for XA transactions and shows how to start the recovery manager in your application.
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-79405884339584305162018-01-11T17:01:00.000+00:002018-01-11T17:06:06.523+00:00Recovery of Narayana jdbc transactional driver<a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html">The post
about jdbc transactional driver</a> introduced ways how you can start to code with it.
The post talks about enlisting JDBC work into the global transaction but it omits
the topic of recovery.<br />
And it's here where using of transactional driver brings another benefit
with ready to use approaches to set up the recovery. As in the prior article
we will work with the jbosstm quickstart
<a href="https://github.com/jbosstm/quickstart/tree/master/transactionaldriver/transactionaldriver-standalone">transactionaldriver-standalone</a>.
<p>
After reading <a href="https://jbossts.blogspot.cz/2018/01/narayana-periodic-recovery-of-xa.html">the post about transaction recovery</a> you will find out that for the recovery manager would consider any resource that we
<a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html">enlist into the global transaction</a>
we have to:<br />
<ul>
<li>either ensure that resource could be serialized into Narayana transaction log store
(resource has to be <a href="https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html">serializable</a>),
in which case the recovery manager deserialize the <code>XAResource</code> and use it directly to get data from it
</li>
<li>or to register recovery counterpart of the transaction enlistment which is capable to provide the instance of <code>XAResource</code>
to the <code>RecoveryModule</code><br />
in other words we need implemntation of <code>XAResourceRecoveryHelper</code> or <code>XAResourceRecovery</code>
(and that's where transactional driver can help us).
</li>
</ul>
<br />
<p>
For configuration of the recovery properties, we use
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml"><code>the jbossts-properties.xml</code></a>
descriptor in our quickstart. We leave the most of the properties with their default values
but we still need to concentrate to set up the recovery.<br />
You can observe that it serves to define recovery modules, orphan filters or xa resource recovery helpers.
Those are important entries for the recovery works for our transaction JDBC driver.<br />
For better understanding what was set I recommend to check the comments there.
</p>
<h2>JDBC transaction driver and the recovery</h2>
<a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html">In the prior article about JDBC driver</a>
we introduced three ways of providing connection data to the transaction manager (it then wraps the connection and
provides transactionality in the user application).
Let's go through the driver enlistment variants and check how the recovery can be configured for them.
<br /><br />
<h3>
XADataSource provided within Narayana JDBC driver properties</h3>
<p>
This is a variant where <code>XADatasource</code> is created directly in the code and then
the created(!) instance is passed to the jdbc transactional driver.<br />
As transactional driver receives the resource directly it does not have clue how to create
such resource on its own during recovery. We have to help it with
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/recovery/Ds1XAResourceRecovery.java#L46">
our own implementation of the <code>XAResourceRecovery</code></a> class.
That has to be of course <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml#L114">registered</a>
into environment bean (it's intentionally commented out as for testing purposes we need to change different variants).
</p>
<br />
<ul>
<li><a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html#driver-provided">link to section of previous blogpost</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverProvidedXADataSource.java">
quickstart class enlisting the resource</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/recovery/Ds1XAResourceRecovery.java">
the implementation class providing the XAResource</a> (in our case pretty dummy one)
</li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L231">testcase with recovery</a></li>
</ul>
<br />
<h3>
XADataSource bound to JNDI</h3>
<p>
This variant bound the <code>XADatasource</code> to JNDI name. The recovery can lookup
the provided jndi name and receive it to create an <code>XAConnection</code> to find the indoubt transactions at database side.<br />
The point here is to pass information about jndi name to the recovery process for it knowing what to search for.<br />
The jdbc driver uses a xml descriptor for that purpose in two variants
</p>
<ul>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/recovery-basicxa-test1.xml">
BasicXARecovery</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/recovery-jdbcxa-test1.xml">
JDBCXARecovery</a></li>
</ul>
<br />
In fact, there is no big difference between those two variants and you can use whatever fits you better.
In both versions you provide the JNDI name to be looked-up.<br />
<ul>
<li><a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html#driver-indirect">link to section of previous blogpost</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverIndirectRecoverable.java">
quickstart class enlisting the resource</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L263">testcase with recovery #1</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L279">testcase with recovery #2</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/jbossts-properties.xml#L103">configuration in the jbossts-properties.xml file</a></li>
</ul>
<br />
<h3>XADataSource connection data provided in properties file</h3>
<p>
The last variant uses <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/resources/ds1.h2.properties">properties file</a>
where the same connection information is used already
<a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverDirectRecoverable.java#L61">during resource enlistment</a>.
And the same property file is then automatically used for recovery. You don't need to set any property manually.
The recovery is automatically setup because the placement of the properties file is serialized into object store and then loaded during recovery.
</p>
<br />
<ul>
<li><a href="https://jbossts.blogspot.cz/2017/12/narayana-jdbc-transactional-driver.html#driver-direct">link to section of previous blogpost</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverDirectRecoverable.java">
quickstart class enlisting the resource</a></li>
<li><a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L247">testcase with recovery</a></li>
</ul>
<p>
In this case you configured the <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverDirectRecoverable.java#L63">PropertyFileDynamicClass</a> providing datasource credentials for the transaction manager and the recovery too.
If you would like to extend the behaviour you can implement your own
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/internal/jdbc/DynamicClass.java">DynamicClass</a> (please consult the codebase).
For the recovery would work automatically you need to work with the
<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jta/classes/com/arjuna/ats/jta/xa/RecoverableXAConnection.java"><code>RecoverableXAConnection</code></a>.
</p>
<br />
<h2>Summary</h2>
<p>
There is currently available three approaches for the setting up recovery of jdbc transactional driver<br/>
creation of your own <code>XAResourceRecovery/XAResourceRecoveryHelper</code> which is feasible if you want to control the creation
of the datasource and jdbc connection on your own. Or using one of the prepared <code>XAResourceRecovery</code> classes - either
<code>JDBCXARecovery</code> or <code>BasicXARecovery</code> where you provide xml file where you specify the JNDI name of the datasource.
The last option is to use properties file which defines credentials for connection and for recovery too.
</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8686578724458335326.post-52844220717510777152017-12-27T08:27:00.000+00:002018-01-18T10:59:33.302+00:00Narayana jdbc transactional driverThe purpose of this blog post is to summarize ways (in current days) how to setup and use Narayana JDBC driver in your standalone application. The text is divided to two parts. Where here in the first we show creating managed connection while in the second we talk a bit about settings for recovery.<br />
<br />
<h3>
Transactional aware JDBC connections</h3>
For working with multiple database connections in transactionaly reliable way<br />
you need either hacking on transaction handling (totally not recommended, a good knowledge of XA specification is necessary) or use transaction manager to that for you.<br />
<br />
<blockquote class="tr_bq">
<i>The word multiple is important here as if you want to run only single database connection you are fine to use local JDBC transaction (Connection.setAutoCommit(false), <a href="https://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#setAutoCommit(boolean)">https://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#setAutoCommit(boolean)</a>). But if you want to manage transactionally multiple JDBC connections (different databases, running at different database accounts...) then you need transaction manager.</i></blockquote>
<br />
If you use a transaction manager for that purpose (expecting running a standalone application) you need to: initialize the transaction manager, begin transaction and enlist each resource with the transaction for transaction manager to know which are those participants that are expected to be finished with ACID guarantees.<br />
<br />
If you use Narayana you have another option to use the Narayana JDBC transaction driver (<a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/jdbc/TransactionalDriver.java">https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/jdbc/TransactionalDriver.java</a>).<br />
JDBC transactional driver makes your life easier as you can configure the driver once and then get a managed connection, wrapped by the transactional functionality and you don't need to care of if anymore.<br />
<a href="https://draft.blogger.com/null" name="own-enlistment"></a>
<h3>
Managing the transaction enlistment on your own</h3>
The first code example shows how to use transaction manager to manage JDBC connection. There is no JDBC transaction driver involved and you manage enlistment manually.<br />
<br />
There is enlisted only one resource in this code example which does not require transaction manager to be used in fact. The main purpose of using transaction manager is for managing two or more distinct resources. Another reason could be the offered JTA API which can make the code clearer.
<br />
<pre><code class="java">// here we get instance of Narayana transaction manager
TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
// and beginning the global transaction for XAResources could be enlisted into
tm.begin();
// getting DB2 datasource which then provides XAResource
XADataSource dsXA = neworg.h2.jdbcx.JdbcDataSource();
// the xa datasource has to be filled with information to connection happens, using setters
dsXA.set...();
// from XADataSource getting XAConnection and then the XAResource
XAConnection xaConn = dsXA.getXAConnection();
// transaction manager to be provided with the XAResource
tm.getTransaction().enlistResource(xaConn.getXAResource());
// the business logic in database in the transaction happening here
PreparedStatement ps = xaConn.getConnection().prepareStatement("INSERT INTO TEST values (?, ?)");
ps.setInt(1, 1);
ps.setString(2, "Narayana");
// statement executed and transaction is committed or rolled-back depending of the result
try {
ps.executeUpdate();
tm.commit();
} catch (Exception e) {
tm.rollback();
} finally {
xaConn.close(); // omitting try-catch block
}
</code></pre>
You can compare approach of using <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/JdbcLocalTransaction.java#L51">JDBC local transaction</a> not ensuring reliable resources management with use of <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/ManagedTransaction.java#L45">Narayana with manual enlistment</a> in the <a href="https://github.com/jbosstm/quickstart">Narayana quickstarts</a>.<br />
<h3>
</h3>
<h2>
Managing the transaction enlistment with use of the JDBC transactional driver</h2>
How is the same task will be with the transaction driver?<br />
First we need an <a href="https://docs.oracle.com/javase/7/docs/api/javax/sql/XADataSource.html">XADataSource</a> to be provided to the transactional driver. Next we request connection from the transactional driver (and not directly from the <code>XADataSource</code>). As we requested the XADatasource from the driver it has chance to wrap it and it controls the connection. Thus the resource is automatically enlisted to an active transaction. That way you don't need to think of getting <a href="https://docs.oracle.com/javase/7/docs/api/javax/sql/XAConnection.html">XAConnection</a> and <a href="https://docs.oracle.com/javase/7/docs/api/javax/sql/XADataSource.html">XADataSource</a> and enlisting them to the transaction and you don't need to pass the transaction and the connection from method to a method as parameter but you can simply use the transactional driver connection withdrawal.<br />
<br />
If you want to use the transactional driver in your project you will need to add two dependencies into configuration of your dependency management system. Here is what to use with maven<br />
<pre><code class="xml"><dependency>
<groupId>org.jboss.narayana.jta</groupId>
<artifactId>narayana-jta</artifactId>
<version>5.7.2.Final</version>
</dependency></code></pre>
<pre><code class="xml"><dependency>
<groupId>org.jboss.narayana.jta</groupId>
<artifactId>jdbc</artifactId>
<version>5.7.2.Final</version>
</dependency>
</code></pre>
There are basically three possibilities how to provide <code>XADataSource</code> to the transactional driver. Let's go through them.<br />
<br />
<a href="https://draft.blogger.com/null" name="driver-provided"></a>
<h3>
XADataSource provided within Narayana JDBC driver properties</h3>
First you can provide directly an instance of <code>XADataSource</code>. This single instance is used for the further connection distribution. This settings is done with property<br />
<i>TransactionalDriver.XADataSource</i>. That key is filled with instance of the XADataSource.<br />
<br />
You can examine this example in <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverProvidedXADataSource.java#L64">Narayana quickstart DriverProvidedXADataSource</a> (two resources in use) and check the functionality in the <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L145">test</a>.<br />
<br />
<pre><code class="java">// XADataSource initialized to be passed to transactional driver
XADataSource dsXA = new org.h2.jdbcx.JdbcDataSource();
dsXA.set...();
// the datasource is put as property with the special name
Properties connProperties = new Properties();
connProperties.put(TransactionalDriver.XADataSource, dsXA);
// getting connection when the 'url' is 'jdbc:arjuna' prefix which determines
// the Naryana drive to be used
Connection con = DriverManager.getConnection(TransactionalDriver.arjunaDriver, connProperties);
// starting transaction
TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
tm.begin();
// db business logic (sql insert query) preparation
PreparedStatement ps = conn.prepareStatement("INSERT INTO TEST values (?, ?)");
ps.setInt(1, 41);
ps.setString(2, "Narayana");
// execution, committing/rolling-back
try {
ps.executeUpdate();
tm.commit();
} catch (Exception e) {
tm.rollback();
} finally {
conn.close();
}</code></pre>
<br />
<a href="https://draft.blogger.com/null" name="driver-indirect"></a>
<h3>
XADataSource bound to JNDI</h3>
Another possibility is using JNDI to bind the <code>XADataSource</code> to and provide the JNDI as part of the url to transactional driver.<br />
<br />
You can examine this example in <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverIndirectRecoverable.java#L56">Narayana quickstart DriverIndirectRecoverable</a> and check the functionality in the <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L169">test</a>.<br />
<pre><code class="java">// the JNDI name has to start with the Narayana transactional driver prefix,
// for would be determined that we want connection of transactional driver
// the suffix (here 'ds') is used as JNDI name that XADataSource will be bound to
XADataSource dsXA = JdbcDataSource ds = new JdbcDataSource();
dsXA.set...();
// binding xa datasource to JNDI name 'ds'
InitialContext ctx = new IntitialContext();
ctx.bind("ds", dsXA);
// passing the JNDI name 'ds' as part of the connection url that we demand
// the first part is narayana transactional driver prefix
String dsJndi = TransactionalDriver.arjunaDriver + "ds";
Connection conn = DriverManager.getConnection(dsJndi, new Properties());
// get transaction driver and start transaction
TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
tm.begin();
// data insertion preparation
PreparedStatement ps = conn.prepareStatement("INSERT INTO TEST values (?, ?)");
ps.setInt(1, 42);
ps.setString(2, "Narayana");
// execute, commit or rollback
try {
ps.executeUpdate();
tm.commit();
} catch (Exception e) {
tm.rollback();
} finally {
conn.close();
} </code>
</pre>
<br />
<a href="https://draft.blogger.com/null" name="driver-direct"></a>
<h3>
XADataSource connection data provided in properties file</h3>
<br />
The third option is about construction a construct of dynamic class. Here the part of the url after the <code>arjunaDriver</code> prefix depends on implementation of interface <code>com.arjuna.ats.internal.jdbc.DynamicClass</code>.<br />
Currently there is an only one provided<code> com.arjuna.ats.internal.jdbc.drivers.PropertyFileDynamicClass</code>.<br />
This expects that the jdbc url contains path to the properties file where connection data for XADataSource class is provided. In particular the property file defines a name of class implementing the <code>XADataSource</code> interface. This name is written in the key <code>xaDataSourceClassName</code>. Next you need to provide connection data (jdbc url, username, password) where each of the properties<br />
is dynamically invoked as a setter on the particular <code>XADataSource</code> instance. Which is exact name of the property depends on the database you and the JDBC driver you use.<br />
<br />
You can examine this example in <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/main/java/io/narayana/DriverDirectRecoverable.java">Narayana quickstart DriverDirectRecoverable</a> and check the functionality in the <a href="https://github.com/jbosstm/quickstart/blob/master/transactionaldriver/transactionaldriver-standalone/src/test/java/io/narayana/TransactionalDriverTest.java#L193">test</a>. <br />
<br />
<pre><code class="java">// jdbc url is defined with path to the properties file
// see the ./ds.properties as 'getConnection' url parameter
Properties props = new Properties();
props.put(TransactionalDriver.dynamicClass, PropertyFileDynamicClass.class.getName());
Connection conn = DriverManager.getConnection(TransactionalDriver.arjunaDriver
+ "./ds.properties", props);
// starting transaction
TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
tm.begin();
// data insertion preparation
PreparedStatement ps = conn.prepareStatement("INSERT INTO TEST values (?, ?)");
ps.setInt(1, 43);
ps.setString(2, "Narayana");
// execute, commit or rollback
try {
ps.executeUpdate();
tm.commit();
} catch (Exception e) {
tm.rollback();
} finally {
conn.close();
}</code>
</pre>
<br />
and the <code>./ds.properties</code> file could look like this. We use H2 jdbc driver and if you check the <a href="https://github.com/h2database/h2database/blob/master/h2/src/main/org/h2/jdbcx/JdbcDataSource.java#L215">API of the driver</a> you will find there setters like <code>setURL</code>, <code>setUser</code> and <code>setPassword</code> which are used to fill connection data after <code>XADataSource</code> is intialized by default constructor.<br />
<pre><code class="java"># implementation of XADataSource
xaDataSourceClassName=org.h2.jdbcx.JdbcDataSource
# properties which will be invoked on dynamically created XADataSource as setters.
# For example there will be call
# JdbcDataSource.setURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1")
URL=jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1
User=sa
Password=sa
</code>
</pre>
<h3>
</h3>
<h2>
In summary</h2>
<br />
Let's put together properties and their usage. The properties used in the transactional driver could be verified in <a href="https://github.com/jbosstm/narayana/blob/master/ArjunaJTA/jdbc/classes/com/arjuna/ats/jdbc/TransactionalDriver.java#L60">the code of TransactionalDriver</a>.<br />
<ul>
<li><code>TransactionalDriver.arjunaDriver</code> (<code>jdbc:arjuna:</code>) is a prefix of jdbc url which defines the Narayana transactional driver is in demand. Data after this prefix is used as parameter for later use.</li>
</ul>
Properties provided at time of connection request defines how to get <code>XADataSource</code> implementation.<br />
<ul>
<li><code>TransactionalDriver.XADataSource</code> when used it defines that implementation of XADataSource was provided as parameter and will be used for connection withdrawal<code> </code></li>
<li><code>TransactionalDriver.dynamicClass</code> defines name of class implementing interface<code> com.arjuna.ats.internal.jdbc.DynamicClass</code> which is then used for dynamically creating of the XADataSource.<code> </code></li>
<li><code>TransactionalDriver.userName</code> and <code>TransactionalDriver.password</code> you can use if you the particular connection needs to be specified with the values. They will be used in call of <code>XADataSource.getXAConnection(username, password)</code>.</li>
<li><code>TransactionalDriver.poolConnections</code> is default as <code>true</code>. The current behavior is simple. There is created a pool for each jdbc
url, internal check verifies if the particular connection is in use, if not then it's passed for the usage otherwise it's created a new connection. The pool capacity is defined by property <code>TransactionalDriver.maxConnections</code>. When the connection is closed then it is returned to the pool and marked as 'not under use'. For some more sophisticated pool management some 3rd party pool management project is recommended. <br />If this property is set to <code>false</code> then a new connection is returned each time is asked for. That way you need to pass this connection over the application.</li>
</ul>
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-80411036201265555532017-12-20T09:14:00.000+00:002017-12-20T09:14:22.124+00:00Narayana LRA: implementation of saga transactionsThe Narayana transaction manager implements <a href="http://jbossts.blogspot.co.uk/2017/06/sagas-and-how-they-differ-from-two.html">saga transactional pattern</a> naming it as LRA which is abbreviation to Long Running Action.<br />
This saga implementation is basis for the specification fitting to schema of Eclipse MicroProfile. See at <a href="https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA">https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA</a>.<br />
<br />
The communication is done over HTTP in way of REST principles.<br />
The Java EE technologies which the LRA builds upon are CDI and JAX-RS.<br />
<br />
<h2>
Saga - what we are talking about</h2>
Before we start talking about LRA let's introduce the term saga.<br />
Saga consists from independent set of operations which all together forms one atomic action. The operation can be whatever action you think.<br />
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb19pKgTTsI7J74LtVHQ2NIE3V4GDUMeB1Euise2eHzPypWKJMcm81LpQQBaK4Ofv7oqLSfIRcMfs0lC4cytVuTwk8kk_jc0DCUxJTr4KKQkUCkOEMdmb5FefxlIpsmKly_2aSW3sjBsU/s1600/saga_confirm.png" imageanchor="1" style="border: 0 none; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="253" data-original-width="1000" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb19pKgTTsI7J74LtVHQ2NIE3V4GDUMeB1Euise2eHzPypWKJMcm81LpQQBaK4Ofv7oqLSfIRcMfs0lC4cytVuTwk8kk_jc0DCUxJTr4KKQkUCkOEMdmb5FefxlIpsmKly_2aSW3sjBsU/s640/saga_confirm.png" width="640" /></a></div>
<br />
<br />
<br />
<blockquote class="tr_bq">
<i>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 <a href="http://queue.acm.org/detail.cfm?id=1394128">http://queue.acm.org/detail.cfm?id=1394128</a>.</i></blockquote>
<br />
Principle of saga requires existence of a compensations actions invoked in case of failure.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDAmA36R4DN6q1QYA-vjqHxYvxfIIO2NRjs0hLALsMXd0xPuZiUrXBYOhiUC6kNctNjqW3ycMqwgtNYOKvdSKH6IKenZu2jv1p5LHraNO72bPyv-E6Gzgoc0E7iDkts6UTbcFKfDGy4jg/s1600/saga_compensate.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="258" data-original-width="1000" height="163" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDAmA36R4DN6q1QYA-vjqHxYvxfIIO2NRjs0hLALsMXd0xPuZiUrXBYOhiUC6kNctNjqW3ycMqwgtNYOKvdSKH6IKenZu2jv1p5LHraNO72bPyv-E6Gzgoc0E7iDkts6UTbcFKfDGy4jg/s640/saga_compensate.png" style="border: 0px none;" width="640" /></a></div>
<br />
<br />
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).<br />
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.<br />
<br />
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.<br />
<br />
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).<br />
<br />
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.<br />
<br />
In summary using saga transactions is a design pattern which needs to be built to the foundation of the application architecture.<br />
<br />
<h2>
LRA - Long Running Actions</h2>
The Narayana LRA is implementation of saga for HTTP transport based on the REST principles. <br />
<br />
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.<br />
<br />
The coordinator can be placed as separate service or it can be attached to the application too. <br />
<br />
For Narayana implementation applies that in case of coordinator packed with the application, the application itself talks to coordinator with in-memory calls.<br />
<br />
Let's explain how the LRA communication works on the example. This is diagram showing our usecase.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg264w5Aogg7eYHjWm3cdyLxhompOVLUtAtErfNARtklDgxRxXSOjmcwjloNBSAMNPF_okWNXN4XA6fbq-QYhFYjKUH1sBappWRjdGldGujZOR8-Gu9pvPCuNfLnwDIq-A_OKsnqwOGG7M/s1600/msa_calls.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="249" data-original-width="1029" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg264w5Aogg7eYHjWm3cdyLxhompOVLUtAtErfNARtklDgxRxXSOjmcwjloNBSAMNPF_okWNXN4XA6fbq-QYhFYjKUH1sBappWRjdGldGujZOR8-Gu9pvPCuNfLnwDIq-A_OKsnqwOGG7M/s640/msa_calls.png" width="640" /></a></div>
<br />
<br />
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<br />
<ol>
<li>A client makes a call to the first service (Microservice #1)</li>
<li>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.</li>
<li>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.</li>
<li>The Microservice #1 takes the LRA identifier and adds it as an HTTP header (<i>long-running-action</i>) 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.</li>
<li>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.</li>
<li>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.</li>
</ol>
<h3>
Code examples </h3>
If you wan to see this example working check out the <a href="https://github.com/redhat-helloworld-msa/helloworld-msa">Red Hat MSA example</a> <br />
<a href="https://github.com/ochaloup/helloworld-msa/tree/lra">enriched with the LRA capabilities</a>.<br />
Detailed installation steps could be found at the page: <a href="https://developer.jboss.org/wiki/MSAQuickstartsWithLRAREST-ATOnMinishift">https://developer.jboss.org/wiki/MSAQuickstartsWithLRAREST-ATOnMinishift</a><br />
<br />
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<br />
<a href="https://github.com/ochaloup/hola/blob/lra/src/main/java/com/redhat/developers/msa/hola/HolaResource.java#L81">https://github.com/ochaloup/hola/blob/lra/src/main/java/com/redhat/developers/msa/hola/HolaResource.java#L81</a><br />
<br />
or check other implementations run with Spring, Vert.x and Node.js<br />
<br />
<ul>
<li><a href="https://github.com/ochaloup/ola/blob/lra/src/main/java/com/redhat/developers/msa/ola/OlaController.java#L94">https://github.com/ochaloup/ola/blob/lra/src/main/java/com/redhat/developers/msa/ola/OlaController.java#L94</a></li>
<li><a href="https://github.com/ochaloup/aloha/blob/lra/src/main/java/com/redhat/developers/msa/aloha/AlohaVerticle.java#L141">https://github.com/ochaloup/aloha/blob/lra/src/main/java/com/redhat/developers/msa/aloha/AlohaVerticle.java#L141</a></li>
<li><a href="https://github.com/ochaloup/bonjour/blob/lra/lib/api.js#L72">https://github.com/ochaloup/bonjour/blob/lra/lib/api.js#L72</a></li>
</ul>
Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8686578724458335326.post-4584289341938721562017-12-18T19:36:00.000+00:002017-12-20T10:48:52.221+00:00Saga implementations comparison<div style="-webkit-text-stroke-width: 0px; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; word-wrap: break-word;">
In the previous <a href="http://jbossts.blogspot.cz/2017/06/sagas-and-how-they-differ-from-two.html" target="_blank">blog post</a> we have investigated the general motions of the <a href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf" target="_blank">saga pattern</a> and how sagas differ from traditional ACID approach. This article will focus on the current state of applicability of this pattern. We will introduce and compare three frameworks that presently support saga processing, namely Narayana LRA, Axon framework and Eventuate.io.
<span style="font-size: large;"><span style="font-family: "verdana" , sans-serif;">Narayana LRA</span></span>
Narayana Long Running Actions is a specification developed by the Narayana team in the collaboration with the Eclipse MicroProfile initiative. The main focus is to introduce an API for coordinating long running activities with the assurance of the globally consistent outcome and without any locking mechanisms.
[<a href="https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA">https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA</a>]
<span style="font-size: large;"><span style="font-family: "verdana" , sans-serif;">Axon framework</span></span>
Axon framework is Java based framework for building scalable and highly performant applications. Axon is based on the Command Query Responsibility Segregation <a href="https://martinfowler.com/bliki/CQRS.html" target="_blank">(CQRS</a>) pattern. The main motion is the event processing which includes the separated Command bus for updates and the Event bus for queries.
[<a href="http://www.axonframework.org/">http://www.axonframework.org/</a>]
<span style="font-size: large;"><span style="font-family: "verdana" , sans-serif;">Eventuate.io</span></span>
Eventuate is a platform that provides an event-driven programming model that focus on solving distributed data management in microservices architectures. Similarly to the Axon, it is based upon CQRS principles. The framework stores events in the MySQL database and it distributes them through the Apache Kafka platform.
[<a href="http://eventuate.io/">http://eventuate.io</a>]
<b>NOTE</b>: CQRS is an architectural pattern that splits the domain model into two separated models - the first one is responsible for updates and the containing business logic while the other is taking care of the reads and providing information for the user.
<span style="font-size: x-large;"><span style="font-family: "verdana" , sans-serif;">Comparisons</span></span>
Even though all of the above frameworks achieve the same outcome there are several areas where we can examine how the handling of the saga processing differ.
<span style="font-family: "verdana" , sans-serif;"><span style="font-size: large;">Developer friendliness</span></span>
The LRA provides for the developer the traditional coordinator oriented architecture. Individual participants can join the LRA by the HTTP call to the LRA coordinator, each providing methods for saga completion and compensation. Narayana provides a LRA client which makes the REST invocations transparent.
In the Axon sagas are implemented as aggregates. The aggregate is a logical group of entities and value objects that are treated as a single unit. Axon uses special type of event listener that allows the developer to associate a property in the events with the current saga so that the framework knows which saga should be invoked. The invocation and compensation are executed by separated event handlers and therefore different events.
Not a long ago Eventuate presented a new API called <a href="https://github.com/eventuate-tram/eventuate-tram-core" target="_blank">Eventuate Tram</a> which handles the saga processing for the platform. It enables applications to send messages as a part of an database transaction. The platform provides abstractions for messaging in form of named channels, events as subscriptions to domain events and commands for asynchronous communication.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; word-wrap: break-word;">
<br /></div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; word-wrap: break-word;">
<span style="font-family: "verdana" , sans-serif;"><span style="font-size: large;">Saga specifications</span></span>
In the LRA the specification of how the saga should be performed is specified by the initiator. Initiating service is able to invoke participants on the provided endpoints which allows participant to join the LRA context. The participant can specify whether to join, create new or ignore the corresponding LRA context by the CDI annotation.
Axon provides a set of annotation the denote the saga class. A <i>@Saga</i> annotation defines the class as a saga aggregate which allows it to declare a saga event handlers. Saga handler can optionally include the name of the property in the incoming event which has been previously associated with the saga. Additionally Axon provides special annotations to mark the start and end of the saga.
In Eventuate the developer is able to specify the saga definition including the participant invocations, compensations and reply handlers in the saga definition. It provides a simple builder which constructs the saga step by step providing the handlers for command and event processing.
<span style="font-size: large;"><span style="font-family: "verdana" , sans-serif;">Failure handling</span></span>
The saga compensating actions are in the LRA defined as designated endpoints. If the initiating service cancels the LRA, the coordinator is able to call the compensation endpoints of the included participants.
In Axon application developers need to know which events represents the failure to provide the correct event listeners. Also the tracking of the progress of the execution as well as the one of the compensation is operated by the developer.
Eventuate registers the compensation handlers in the saga definitions. Participants are allowed to send a special build-in command which indicates failure a therefore the compensation of the previous actions.
<span style="font-size: large;"><span style="font-family: "verdana" , sans-serif;">Ordering of invocations</span></span>
LRA and Eventuate invoke each participant in strict order. This approach expects the actions to be dependent on each prior action so the compensations are called in reverse order.</div>
<div style="-webkit-text-stroke-width: 0px; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; word-wrap: break-word;">
<b>NOTE</b>: Narayana LRA allows participants to modify this behavior by returning HTTP 202 Accepted.
Axon on the contrary does not control the ordering of invocations so the programmer is allowed to send the compensation commands in any desired ordering.
<span style="font-family: "verdana" , sans-serif;"><span style="font-size: large;">Structure and failure recovery</span></span>
As Axon and Eventuate are primarily CQRS based frameworks they require some additional handling for the saga execution. In Axon saga is still the aggregate which means that it consumes commands and produces events. This may be an unwanted overhead when the application does not follow the CQRS domain pattern. The same applies to Eventuate Tram but as the communication is shadowed through the messaging channels it does not force the programmer to follow CQRS. Both platforms mark every event and command into the distributed event log which warrants the saga completion upon the system failure with the eventual consistency.
The LRA on the other hand requires only to implement processing and compensation endpoints. Processing is then handled by the LRA coordinator and it is made transparent to the end users. The failures of the coordinator can be managed by replication and/or transaction log. A participant failure is treated by the custom timeout on the saga invocation after which the coordinator cancels the saga.
<span style="font-family: "verdana" , sans-serif;"><span style="font-size: x-large;">Conclusion</span></span>
We have discussed the main advantages and drawbacks of each platform respectively. As a part of my thesis I have created a basic example in all of the discussed frameworks. It is a simple ordering saga containing requests for shipment and invoice computation invoked on different services. In the next blog post I plan to describe the execution of this saga in every framework to discuss the main distinctions in grater detail.
- <a href="https://github.com/xstefank/axon-service">https://github.com/xstefank/axon-service</a>
- <a href="https://github.com/xstefank/eventuate-service">https://github.com/xstefank/eventuate-service</a> - pure CQRS solution
- <a href="https://github.com/xstefank/lra-service">https://github.com/xstefank/lra-service</a>
- <a href="https://github.com/xstefank/eventuate-sagas">https://github.com/xstefank/eventuate-sagas</a> - Eventuate Tram
</div>
Anonymoushttp://www.blogger.com/profile/14066310690870874549noreply@blogger.com1tag:blogger.com,1999:blog-8686578724458335326.post-36338437308954769132017-11-08T15:01:00.000+00:002017-11-08T15:22:11.200+00:00Software Transactional Memory for the Cloud at µCon London 2017I have just returned from <a href="https://skillsmatter.com/conferences/8549-con-2017-the-microservices-conference">µCon London 2017: The Microservices Conference</a>. I was down there talking about our <a href="http://narayana.io//docs/project/index.html#d0e16064">Software Transactional Memory implementation</a> which our regular readers may recall was first introduced by <a href="http://www.blogger.com/profile/15072917010265365428">Mark</a> back in <a href="http://jbossts.blogspot.co.uk/2013/03/stm-vertx-and-pi-part-1.html">2013</a>. In particular I wanted to show how it can be used with the actor model features of <a href="http://vertx.io/">Vert.x</a> and the nice scaling features of <a href="https://www.openshift.com/">OpenShift</a>.<br />
<br />
I have put the <a href="https://github.com/jbosstm/conferences/blob/master/mucon2017/Mucon2017TransactionalActors.pdf">presentation slides</a> in the narayana git repo so feel free to go and take a look to see what you missed out on. You can also access the source code I used for the practical demonstration of the technology from the same repository. The abstract for the talk gives a good overview of the topics discussed:<br />
<blockquote class="tr_bq">
<br />
<i>"Vert.x is the leading JVM-based stack for developing asynchronous, event-driven applications. Traditional ACID transactions, especially distributed transactions, are typically difficult to use in such an environment due to their blocking nature. However, the transactional actor model, which pre-dates Java, has been successful in a number of areas over the years. In this talk you will learn how they have been integrating this model using Narayana transactions, Software Transactional Memory and Vert.x. Michael will go through an example and show how Vert.x developers can now utilise volatile, persistent and nested transactions in their applications, as well as what this might mean for enterprise deployments."</i></blockquote>
<br />
And the demo that this abstract is referring to is pretty trivial but it does serve to draw out some of the impressive benefits of combining actors with STM. Here's how I introduced the technology:<br />
<br />
<ol>
<li>Firstly I showed how to write a simple Vert.x flight booking application that maintains an integer count of the number of bookings.</li>
<li>Run the application using multiple Vert.x verticle instances.</li>
<li>Demonstrate concurrency issues using parallel workloads.</li>
<li>Fix the concurrency issue by showing how to add volatile STM support to the application.</li>
</ol>
<br />
I put the <a href="https://github.com/jbosstm/conferences/tree/master/mucon2017/demo_without_STM">without STM</a> and the <a href="https://github.com/jbosstm/conferences/tree/master/mucon2017/demo_with_STM">with STM</a> versions of the demo code in the same repository as the presentation slides.<br />
<br />
I then showed how to deploy the application to the cloud using a single-node OpenShift cluster running on my laptop using Red Hat's <a href="https://www.openshift.org/minishift/">minishift</a> solution. For this I used "persistent" STM which allows state to be shared between JVMs and this gave me the opportunity to show some of the elastic scaling features of STM, Vert.x and OpenShift.<br />
<div>
<br /></div>
Michael Musgrovehttp://www.blogger.com/profile/11287095167651465976noreply@blogger.com0