Whengetting back to your question. It would be good to know what's your expectation (and architecture of your application). As you posted the example of the Narayana and Spring boot integration, do you run with Spring boot? Do you use some clustering solution over nodes/pods (or only one node is used)? Do you have e.g. some loadbalancing in front of your app (then you probably need a stickysession with the requests to Narayana node)?
What is needed to understand is that Narayana, in its current state of development, is "a stateful" component. Progress of XA transaction is needed to be persisted somewhere. Narayana has to be able to access that persistent storage to finish with the XA transaction and the storage has to be available to the Narayana even after the container/pod restarts.
If you use the file system then probably the best way to go is to use the StatefulSet. When node is started you claim the PV which is bound to the particular pod. When the pod crashes, the pod is relocated or the app is restarted with a new version then the partition is still available to the particular pod. Narayana is then capable to access the data and finish all unfinished XA transactions even after restart.
If you use the JDBC storage then you may use the StatefulSet as well. What is important is that the pod should be bound to the particular connection - database - database table. After the pod is restarted it still needs to be able to access the same storage.
The second important point from the perspective of XA transaction recovery in Narayana is that the configuration needs to specify unique node identifier. That identifier needs to be bound the same for the Narayana instance at the pod and the storage that's used.
Depending what runtime you use the node identifier could be configured differently. For standalone Narayana the configuration is done with xml descriptor (e.g. here narayana/jbossts-properties.xml at master jbosstm/narayana GitHub) or with system properties of the same name.
From what was said the StatefulSet is, I think, currently the best option how to configure Narayana on Kubernetes. If you use the file system, then you should mount the Narayana object store to the StatefulSet PV and the node identifier should be defined as name of the StatefulSet pod.
On top of that you need to take care when you scale down the StatefulSet (you decreases the number of pods). In such case you need first check that Narayana finished all the transactions (the object store is clean) and then you can remove the pod from the StatefulSet. Otherwise you risk the transaction data inconsistencies.
2. The node id must be unique and must be used in combination with the object store used for any previous execution of the transaction manager with this node id, this is of fundamental importance for data integrity
Suppose I have Narayana JTA running (as a JTA-compliant transaction manager). Suppose further I have a JPA implementation running (EclipseLink, say) that "knows" that a JTA transaction manager is in the picture, such that its EntityManagers are under JTA control. Now suppose that I have a non-XA DataSource I wish to use to back JPA's . I am not, as a user, interested in distributed transactions, in other words, but I do want to take advantage of injected EntityManagers, which are required by specification to be JTA controlled. This is a very common case.
If I wanted to use the HikariCP connection pool, which doesn't support XA itself, but is otherwise an excellent connection pool, I could tell it to pool Narayana JDBC driver URLs. I would also need to tell the Narayana transactional driver not to do any pooling of its own. Is that correct? So Hikari would pool Narayana JDBC driver URLs, which, indirectly, would effectively route to XADataSources. Is that right?
One of the properties that I would supply in such a case would be a means of acquiring the XADataSource that the Narayana JDBC driver wraps. I would (for my purposes) set the dynamicClass property (if I remember right). Is that right?
Then magic happens, and even with the default auto commit settings in play two INSERT statements would get rolled back when the JTA transaction rolls back. And it is the Narayana transactional driver that somehow makes this happen (that's sort of the part I'm missing).
Now, as it happens, I don't actually care about XA. I'm only ever going to use a connection to a single database (let's say). But it appears to me that the data source supplied to JPA via must be XA-capable (even if it wraps a non-XA capable data source under the covers). Otherwise in the case of transaction rollbacks the various SQL statements that might have gone to the database could be visible after the rollback (there are many examples on the web of people being bitten in this way). Does the Narayana driver somehow solve this problem as well? Does it allow a non-XA DataSource to somehow "play nice" with the JTA controller, or must I always supply an XADataSource to the Narayana transactional driver?
First from the general perspective. Narayana implements the JTA specification. The JTA works with XAResources not with JDBC connections. For Narayana would be able to work with JDBC the JDBC has to provide the XAResource interface from its part. The JDBC specification defines the package 'javax.sql' which is that bridge between the simple JDBC ('java.sql') and JTA ('javax.transaction.xa'). It's responsibility of the JDBC to provide the XAResource for Narayana. If JDBC provides the XAResource and we know the Narayana is able to consume the resource there has to be something that integrates (glues) those two parts. It's usually some runtime (like WildFly, Spring, Quarkus...) or some library for more standalone usage (like Narayana JDBC driver or Agroal).
On top of this "gluing" there is another point which is not solved with the "Narayana - - JDBC driver". Which is the pooling of connections. The Narayana JDBC driver, Ironjacamar or Agoral do the both - they are able to glue Narayana with JDBC XA driver code plus they are capable to pool the connections.
If you want Hikari would be for pooling and the Hikari does not provies the JDBC XA interfaces then you will need to have a wrapper that will provides the implementation of those interfaces on top. I think the Narayana JDBC driver (even the dynamic class) won't be capable to provide this out of the box. I think you will need to write some extensions here. But I think you could need only for the wrapper implementing the XADatasource (XADataSource (Java Platform SE 8 ) ) (but that should probably means implicitly to implement XAConnection, XAResource...). While in your case you don't need the "prepare" functionality and you can ignore that.
Regarding of the glue code it depends how you want to work with the JTA implementation. But it's good to have that "gluing" code for easier usage. If you have the "wrapper" created then it should be fine to use the Narayana JDBC driver and the dynamic class with no pooling.
Suppose I were to patch HikariCP's DataSource implementation to also implement XADataSource, together with some means of acquiring a TransactionManager (Narayana or not). Wouldn't the actual pooling mechanism have to change, since JTA transactions must be pinned to a thread? Wouldn't that mean that I would have to make sure that the HikariCP DataSource would be physically pinned to a thread?
I assume you will need to enhance the HikariCP to provide the XADataSource. I think it could be just a thin layer wrapping the Datasource itself (where you throw some UnsupportedOperationException on prepare). Working with the TransactionManager will be the task for the Narayana JDBC driver.
I assume the HikariCP will be configured with a JDBC connection data to get connection to database. HikariCP then provides the XADataSource that will be integrated with Narayana by you write implementation of the narayana/DynamicClass. The JDBC driver should always acquire a new connection without pooling.
The HikariCP provides a connection which is taken from the pool. At time you close the connection the connection is returned to HikariCP pool and it's available for next use. The linking of the datasource to transaction (which effectively means binding it to the thread as a thread local variable) will be done in the Narayana JDBC driver code when it aquires the connection from HikariCP.
But as JDBC driver is currently used mainly by us for testing and experimental purposes I would be a afraid that this setup won't be checking some error cases. E.g. when thinking about this I have no idea what happens when HikariCP has no available connection for the JDBC driver. These types of cases would need to be tested and you are more than welcome to provide the PR with such adjustments ;-)
We have a quickstart using IronJacamar but the xa-datasource would need to be changed to a non-xa datasource: quickstart/h2-xa-ds.xml at master jbosstm/quickstart GitHub - you could reach out to the IronJacamar community over here for guidance on settings to allow a datasource to be wrapped as a LRCO resource. That quickstart uses a second XA resource too which you would not want to do: quickstart/CustomerManager.java at master jbosstm/quickstart GitHub
Basically, when a transaction starts (as detected by @Observes @Initialized(TransactionScoped.class)), I ensure that connections coming from any non-JTA DataSource implementation (HikariCP in this case) are "pinned" to the current thread. I also deactivate their close and autocommit abilities. Then I register a synchronization with the transaction manager such that when the transaction commits I call commit() on the connection and when the transaction rolls back I call rollback(). Then I "unpin" the connection, closing it if necessary. Works great and does not require XA interfaces to be implemented.
3a8082e126