Unexpected behaviour of the persistence if EJB's are invoked remote inside of a server application in EAP6
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 6.x
- 7.0.x
Issue
- If a Java EE application use a second EJB application which is depoyed on other server instances, which might be clustered, multiple invocations are routed to different servers.
Sometimes the invocations are successful, but there are situations where one of the invocations in that sequence is not able to read data which was written before or even read stale data.
This behaviour is different to former EAP versions where the same application worked correct. - Is it possible to have a Sticky policy for Node selection for EJB client to invoke stateless session beans?
- EAP 4 provide a TransactionStickyLoadBalancer policy to be able to use container managed persistence, is there a similar policy in EAP 6?
Resolution
To prevent from having issues with transactional caches remote EJB invocations need to be sticky on an application base to stick with the same PersistenceManager for the same type of Entities.
An example implemenation is attached to this article. Please note that this is an example and it is outside the scope of the posted Service Level Agreements and support procedures.
At the moment we are working to provide a workaround with a TxStickyNodeSelector.
The final solution will be automatical sticky for running transactions which is tracked by This content is not included.Bug 1190996
Root Cause
The cause are two issues if JPA Entities are used as the PersistenceManager will cache results as long as the transaction is active.
- First the transactional behaviour for EJB invocations has changed in EAP6 and the remote EJB invocation from server to server is automatically part of the same transaction, see This content is not included.Bug 1190996 for more details.
- this depends on the transaction annotation if CMT is used
- the source must have already a started transaction
- the destination EJB must continue the transaction with @Required, @Supports, @Mandatory
- The 'client' EJB use transactional caching like the Hibernate implementation of JPA or the JBoss EJB2 CMP implementation.
In this case the persistence might cache values which are read from the database and did not refresh it if the same transaction is running, or change the entity in memory but did not flush it to the database.
This will have stale reads in the following situations:
-
a get - update - get sequence
-
- an EJB is called to read some data
- Entity(A) is read at server1
-
- an EJB is called to update the same data
- Entity(A) is updated at server2
-
- an EJB is called to process the same data
- Entity(A) is read again at server1 where the data is already read from the PersistenceManager
==> The PM will use the already cached Entity(A) and return stale data
-
-
update - get sequence without flush
-
- an EJB is called to process some data
- Entity(A) is updated at server1, but the PersistenceManager decide to not flush the updates to the database as the transaction is not committed
-
- an EJB is called to continue
- Entity(A) is read at server2 to continue
==> The PM will read the Entity(AS from the database which is current out of sync and return stale data
-
Diagnostic Steps
- Is the remote application clustered or deployed to multiple (unclustered) servers?
- Are there multiple remote EJB invocations within the same transaction
- Is the same Entity accessed in that invocations
Related articles
- How to implement a custom loadbalancing policy for EJB calls in EAP6
- The EJB invocations are not well balanced across my clustered EAP6 servers
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.