How do I connect with play persistence (JPA) in Akka actors? - java

I'm using play framework and JPA. Few messages are passed to the Akka Actors to async processing. Inside async process, I need to connect my database through JPA.
public class OrderCreation extends UntypedActor {
private EntityManagerFactory emFact = null;
private ActorSelection provisioner;
#Transactional(readOnly = false)
#Override
public void onReceive(Object order) throws Exception {
//HERE I need to do JPA related transactions
}
#Override
public void postStop() throws Exception {
}
#Override
public void preStart() throws Exception {
provisioner =getContext().actorSelection("/user/OrderProvisioner");
emFact = Persistence.createEntityManagerFactory("test-data-play");
}
}
I got this error
[akka://application/user/OrderCreation] No EntityManager bound to this thread. Try wrapping this call in JPA.withTransaction, or ensure that the HTTP context is setup on this thread.
java.lang.RuntimeException: No EntityManager bound to this thread. Try wrapping this call in JPA.withTransaction, or ensure that the HTTP context is setup on this thread.
at play.db.jpa.JPA.em(JPA.java:58)
Anybody has an idea to connect JPA through Akka?

#Transactional is an action composition, it will only work in Controllers.
You need to inject JPAApi in your actor and use jpaApi.withTransaction method to create/attach EntityManager to the thread and wrap you code within a transaction.

Related

Async is not running in parallel. Spring Boot [duplicate]

I am having troubles invoking a method asynchronously in Spring, when the invoker is an embedded library receiving notifications from an external system. The code looks as below:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
private NotificationClient client;
#Override
public void process(Notification notification) {
processAsync(notification);
}
#PostConstruct
public void startClient() {
client = new NotificationClient(this, clientPort);
client.start();
}
#PreDestroy
public void stopClient() {
client.stop();
}
#Async
private void processAsync(Notification notification) {
// Heavy processing
}
}
The NotificationClient internally has a thread in which it receives notifications from another system. It accepts a NotificationProcessor in its constructor which is basically the object that will do the actual processing of notifications.
In the above code, I have given the Spring bean as the processor and attempted to process the notification asynchronously by using #Async annotation. However, it appears the notification is processed in the same thread as the one used by NotificationClient. Effectively, #Async is ignored.
What am I missing here?
#Async (as well as #Transactional and other similar annotations) will not work when the method is invoked via this (on when #Async is used for private methods*), as long as you do not use real AspectJ compiletime or runtime weaving.
*the private method thing is: when the method is private, then it must been invoked via this - so this is more the consequence then the cause
So change your code:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
#Resource
private DefaultNotificationProcessor selfReference;
#Override
public void process(Notification notification) {
selfReference.processAsync(notification);
}
//the method must not been private
//the method must been invoked via a bean reference
#Async
void processAsync(Notification notification) {
// Heavy processing
}
}
See also the answers for: Does Spring #Transactional attribute work on a private method? -- this is the same problem

Implementing EventProcessingConfigurer,registerErrorHandler to properly handle #EventHandler errors

I am trying to add a ErrorHandler via the EventProcessingConfigurer.registerErrorHandler() method and while it is showing on the configuration the class itself is not being called.
Am currently using Axon 4.1.1 (With out Axon server) and Spring Boot 2.1.6.RELEASE.
i have based my code off github/AxonFramework but it isn't acting the same.
Config:
#Autowired
public void configure(final EventProcessingConfigurer config) {
TestErrorHandler testErrorHandler = new TestErrorHandler();
config.registerErrorHandler("SolrProjection", configuration -> testErrorHandler);
}
ErrorHander:
public class TestErrorHandler implements ErrorHandler, ListenerInvocationErrorHandler {
#Override
public void handleError(final ErrorContext errorContext) throws Exception {
System.out.println("TestErrorHandler.handleError()");
}
#Override
public void onError(final Exception exception, final EventMessage<?> event, final EventMessageHandler eventHandler) {
System.out.println("TestErrorHandler.onError()");
}
}
Projection:
#Configuration
#RequiredArgsConstructor
#ProcessingGroup("SolrProjection")
public class SolrProjection {
#EventHandler
public void onEvent(final TestEvent event,
#SequenceNumber Long sequenceNumber,
#Timestamp final Instant requestTimestamp,
#MessageIdentifier final String messageIdentifier,
final MetaData metaData) {
if (true) {
throw new IllegalStateException();
}
}
even thou i am directly throwing an error, i do not ever see the two system.out's in console. and putting log statements in the #EventHandler are properly being called.
The ErrorHandler is tasked to dealing with different exceptions than what you expect.
When it comes to handling events, Axon Framework deduces two layers:
The internal EventProcessor layer
The Event Handling Components written by framework users
Exceptions thrown within the EventProcessor are dealt with by the ErrorHandler you've configured.
For customizing the process for handling exceptions from your own Event Handlers, you
will have to configure the ListenerInvocationErrorHandler.
To configure a general/default ListenerInvocationErrorHandler, you can use the following method in your first snippet:
EventProcessingConfigurer#registerDefaultListenerInvocationErrorHandler(
Function<Configuration, ListenerInvocationErrorHandler>
)
You can also check out Axon's Reference Guide at this page for more info on this.
Hope this helps you out #sherring!

Set pessimistic lock on entity with EntityManager

Consider the following situation:
We receive a request from a web service which updates our entity. Sometimes we might get two requests at (almost) the same time. We had situations in which our entity looked completely wrong, because of concurrent updates. The idea is to lock the entity pessimistic so that whenever the first request comes it instantly locks the entity and the second request can't touch it (Optimistic locking is no alternative for us). I wrote an integration test to check this behaviour.
I got an integration test which looks like the following:
protected static TestRemoteFacade testFacade;
#BeforeClass
public static void setup() {
testFacade = BeanLocator.lookupRemote(TestRemoteFacade.class, TestRemoteFacade.REMOTE_JNDI_NAME, TestRemoteFacade.NAMESPACE);
}
#Test
public void testPessimisticLock() throws Exception {
testFacade.readPessimisticTwice();
}
which calls the bean
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class TestFacadeBean extends FacadeBean implements TestRemoteFacade {
#EJB
private FiolaProduktLocalFacade produkt;
#Override
public void readPessimisticTwice() {
produkt.readPessimisticTwice();
}
}
with produkt being a bean itself
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class ProduktFacadeBean implements ProduktLocalFacade {
#Override
public void readPessimisticTwice() {
EntityManager entityManager = MyService.getCrudService().getEntityManager();
System.out.println("Before first try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("Before second try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("After second try.");
}
}
with
public class MyService {
public static CrudServiceLocalFacade getCrudService() {
return CrudServiceLookup.getCrudService();
}
}
public final class CrudServiceLookup {
private static CrudServiceLocalFacade crudService;
private CrudServiceLookup(){
}
public static CrudServiceLocalFacade getCrudService() {
if (crudService == null)
crudService = BeanLocator.lookup(CrudServiceLocalFacade.class, CrudServiceLocalFacade.LOCAL_JNDI_NAME);
return crudService;
}
public static void setCrudService(CrudServiceLocalFacade crudService) {
CrudServiceLookup.crudService = crudService;
}
}
#Stateless
#Local(CrudServiceLocalFacade.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Interceptors(OracleDataBaseInterceptor.class)
public class CrudServiceFacadeBean implements CrudServiceLocalFacade {
private EntityManager em;
#Override
#PersistenceContext(unitName = "persistence_unit")
public void setEntityManager(EntityManager entityManager) {
em = entityManager;
}
#Override
public EntityManager getEntityManager() {
return em;
}
}
The problem that arises now is: If I start the integration test once with a breakpoint at System.out.println("Before second try."); and then start the integration test a second time, the latter one can still read MyEntity. Remarkable is that they were different instances (I made this observation on the instanceId in debug mode). This suggests that the entityManager didn't share his hibernate context.
I made the following observations:
Whenever I call a setter on entity and save it to the db, the lock is aquired. But this is not what I need. I need the lock without having modified the entity.
I tried the method entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE) as well, but the behaviour was the same.
I found Transaction settings in DBVisualizer. At the moment it is set to TRANSACTION_NONE. I tried all the others (TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE) as well, without any success.
Let the first thread read the entity, then the second thread read the same entity. Let the first tread modify the entity and then the second modify it. Then let both save the entity and whoever saves the entity last wins and no exceptions will be thrown.
How can I read an object pessimistic, that means: Whenever I load an entity from the db I want it to be locked immediately (even if there was no modification).
Both ways you describe ie.
em.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE)
em.lock(entity, LockModeType.PESSIMISTIC_WRITE)
hold a lock on the related row in database but only for the the entityManager lifespan, ie. for the time of the enclosing transaction, the lock will be so automatically released once you've reached the end of the transaction
#Transactional()
public void doSomething() {
em.lock(entity, LockModeType.PESSIMISTIC_WRITE); // entity is locked
// any other thread trying to update the entity until this method finishes will raise an error
}
...
object.doSomething();
object.doSomethingElse(); // lock is already released here
Have you tried to set the isolation level in your application server?
To get a lock on a row no matter what you are trying to do afterwards (read/write), you need to set the isolation level to TRANSACTION_SERIALIZABLE.
Lock fails only if another thread is already holding the lock. You can take two FOR UPDATE locks on single row in DB, so it's not JPA-specific thing.

Background thread throwing HibernateException - "No Hibernate Session bound to thread..."

I need to create a process that will query a webservice to extract information, and then save the data in my database. However, because this process is very time-intensive, I would like to make it run in the background.
Currently, I have a ProcessHandler which is invoked by a button in the UI. This handler creates a Thread which should run the process in the background. However, I am getting HibernateException with the message No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
I have defined ProcessHandler in one of the config xml files (there are several) as follows (this is a very generic definition):
<bean class="com.project.ProcessHandler" parent="parentHandler" />
Inside ProcessHandler, the code to invoke this process is also very generic:
Thread t = new Thread(new WorkerThread(alphaManager, bravoManager, charlieManager));
t.start();
This is the current implementation of WorkerThread:
public class WorkerThread implements Runnable {
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public WorkerThread() {
this.alphaManager = null;
this.bravoManager = null;
this.charlieManager= null;
}
public WorkerThread(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Override
public void run() {
// code to query webservice and extract data...
saveToDbMethod(data);
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
The default constructor is a leftover from when I tried to define WorkerThread as a bean in (one of) my config xml files.
Can anyone help me by giving me some tips on how to troubleshoot this?
The problem is that you create the Thread manually and expecting it behave like a spring managed bean.
As the ProcessHandler is a legitimate bean, what i would do is following:
1) Create a seaparate service class which would have the managers as dependencies and that #Transactional method:
#Service
public class Service{
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public Service(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
2) Inject the Service into the ProcessHandler:
<bean class="com.project.ProcessHandler" parent="parentHandler">
<property name="service" ref="service">
</bean>
3) Finally pass the Service to the WorkerThread:
public class WorkerThread implements Runnable {
private Service service;
public WorkerThread(Service service) {
this.service = service;
}
#Override
public void run() {
// code to query webservice and extract data...
service.saveToDbMethod(data);
}
}
and:
Thread t = new Thread(new WorkerThread(service));
t.start();
Now your operations should be transactional and within a session.

Spring boot transaction cannot work in timer

I have a transaction like below,
#Transactional
public void changeJobStatus(Long jobId){
JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
...
}
And findOneForUpdate is to lookup database with pessimistic lock,
public interface JobRepository extends CrudRepository<JobEntity, Long>{
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query("select j from JobEntity j where j.id = :id")
JobEntity findOneForUpdate(#Param("id") Long id);
}
This works well, if I call changeJobStatus normally.
But when calling in a TimerTask like below,
TimerTask task = new TimerTask() {
#Override
public void run() {
changeJobStatus(jobId);
}
};
timer.schedule(task, waitTime);
there would be an exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
Why this happens? And if there is a way to call transaction in a TimerTask?
The call to changeJobStatus() is effectively direct to your bean (self-invocation), and therefore not subject to the usual Spring proxying when calling between beans. For this reason no transaction is getting started.
See: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations search for "self-invocation".
There may be several potential ways to approach this:
You could auto-wire a reference to your own bean, which would be fulfilled with a proxy, and call thru that;
You could use mode="aspectj", which performs bytecode weaving (enhancement).
You could control the transaction manually via PlatformTransactionManager;
My approach would depend on whether this is isolated, or a common case. If common, I'd investigate "aspectj" mode; but I would probably hope that it were an outlier and I could stick to the standard Spring "proxy" mode.
This is caused by Spring's AOP limitation. As Thomas has suggested, controlling transaction manually can solve this problem, rather than using #Transactional. Here is the detail implementation,
I have created an simple transaction service like below,
#Service
public class SimpleTransactionService {
private final TransactionTemplate transactionTemplate;
#Autowired
public SimpleTransactionService(PlatformTransactionManager transactionManager){
transactionTemplate = new TransactionTemplate(transactionManager);
}
public void executeTransaction(ITransactionService task){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
task.transactionExecute();
}
});
}
}
ITransactionService is just an simple interface with one method,
public interface ITransactionService {
void transactionExecute();
}
Here is how I use above in my TimerTask,
public void addTimerTask(Object param, Long waitTime){
TimerTask task = new TimerTask() {
#Override
public void run() {
simpleTransactionService.executeTransaction(() -> someOperation(param));
}
};
timer.schedule(task, waitTime);
}
someOperation is the actual transaction executed. With the simple transaction service and a lambda, transaction can be done without any annotation.

Categories