Sending rabbitMQ events after transaction commit - spring

I have big task in transaction (#Transactional method). In this task the id-s are collected and then after transaction commit they must be sent to RabbitMQ (with convertAndSend-method). The RabbitMQ-listener in the other side takes the ids and updates the statuses in DB (it's important to update statuses after transaction changes because only after them the updated data is actual)
I have next questions:
What is the best way to use like the hook in the end (commit) of transaction? I need make the one "afterCommit" method for several service classes (many transactional-methods);
What need I use as the storage of ids? I have thought about smth like ThreadLocal variable but this is not a variant - if there is the parallelStream, the new Thread is created;
May be some other solution?
I have read about the delay RabbitMQ plugin but it is not the variant 4 my task - their time is very different.

Looking at the tags in your question I suppose you are using the spring framework.
So you could use Spring Events and its ApplicationEventPublisher to publish your specific ApplicationEvent together with all the necessary data (the ids in your case).
Spring allows you to bind an event listener to a phase of the current transaction. Just use the #TransactionalEventListener annotation on a method that sends the data to RabbitMQ finally. Binding is possible to different transaction phases. With the default binding (AFTER_COMMIT) the event will only be fired if the transaction has completed successfully.
This Baeldung article on Spring Events is a nice place to find more detailed information.

Related

How can I do sendAndReceive with Spring EventListener?

With the (meanwhile deprecated) reactor-bus from project-reactor I had the API eventBus.sendAndReceive(Event e, Consumer<?> callback).
This allowed to trigger execution by publishing an event and automatically subscribe to a response.
With Spring eventListeners I can publish another event from an EventListener method, but I am missing the feature to directly subscribe to a return value.
How do I achieve the same behaviour with spring? How do I programmaticcaly register/unregister listeners and how do I make the topics dynamic?
With Spring's ApplicationEventMulticaster you can't subscribe to a response. You probably noticed that the onApplicationEvent method returns void! The reason for this is because literally all it does is either call the Subscriber (i.e. ApplicationListener) synchronously, or runs the listener method asynchronously on an executor without returning any type of Future.
Spring's Project Reactor evolved a while ago to match the Reactive Manifesto and similar frameworks (like RxJava) more closely. Now with Spring 5 (with which Reactor comes with by default) you can use Reactor and RxJava interchangeably.
That being the case, regarding your questions:
How do I achieve the same behaviour with spring?
You use the new version of Reactor Core and the functional programming features of Flux, Mono, etc.
With Spring eventListeners I can publish another event from an
EventListener method, but I am missing the feature to directly
subscribe to a return value.
If you look at the API for Flux, you'll see that it has a fluent and functional API (in some ways similar to Java 8 streams).
Flux.just(1, 2, 3, 4)
.map(value -> value + 1)
.subscribe(subscriber::function);
This way, you can operate on your "events" (i.e. 1,2,3,4 in this example), perform an operation on what would be a "return value" for those events, and then pipe those to some subscriber operation to consume those events.
How do I programmaticcaly register/unregister listeners and how do I
make the topics dynamic?
You should take a look at this SO answer.
To register/unregister, that's something you can do with what you might call "completors" in the Reactor framework. See the take functions in the Reactor API. They will signal upstream that they basically want to be unsubscribed, and that the upstream producer should stop emitting.

Spring - JPA - observe events

I would like to observe when an entity is saved or deleted so that I may perform additional activities pertaining to that entity. I thought I did this in the past WITHOUT using the #EntityListeners annotation on the entity class itself because my entity listeners would be implemented in the service layer and NOT in the model / data layer.
The only other way I can think of to do it is inside the persistence.xml and specify my listeners there.
Are there any alternate approaches?
I did this a long time ago in a galaxy far, far away, and the answer was in my question.
The solution (that I wanted, but disliked because of using XML) was to:
write a generic entity listener using annotations, and get a programmatic instance of the bean manager (CDI), or equivalent in spring, then fire an event which I can process either via CDI or spring
where I want that listener to work, place a persistence.xml file and manually specify the entity-listeners there
if I want to do anything special, I simply observe the event that I'm interested in and I get the information that I want.

Spring-Cloud, Hystrix and JPA - LazyInitializationException

I have the following problem trying to integrate Hystrix into an existent Spring Boot application. I am using boot with spring data (jpa repositories). The structure of the app is pretty simple,
we have Resources -> Services -> Repositories.
I enabled Hystrix support and annotated one of the service methods that returns an entity as follow:
#HystrixCommand(fallback="getDealsFallback")
public Page<Deal> getDeals(...) {
// Get the deals from the Index Server.
return indexServerRepository.findDealsBy(...);
}
public Page<Deal> getDealsFallback(...) {
// If IndexServer is down, query the DB.
return dealsRepository.findDealsBy(...);
}
So this works as expected, the real problem resides actually when I return the Entity to the client. I am using OpenEntityManagerInViewFilter so I can serialize my model with its relations.
When I use #HystrixCommand in my service method, I get a LazyInitializatioException when It tries to serialize.
I know the cause (or at least I suspect what is the problem), and is because Hystrix is executing in another thread
so is not part of the transaction. Changing the Hystrix isolation strategy from THREAD to SEMAPHORE, works correctly since its the same thread, but I understand that is not the correct way to approach the problem.
So my question is, How can I make the Hystrix executing thread be part of the transaction. Is there any workaround that I can apply?
Thanks!
It is a little old thread, but maybe someone meets this problems too. There is an issue in github about this.
The reason is, hystrix will run in separate thread, which is different from where the previous transaction is. So the transaction and serialization for lazy will not work.
And the 'THREAD' is the recommended execution strategy too. So if you want to use both hystrix and transaction, you should use them in 2 level calls. Like, in first level service function, use transaction, and in second level service function, use hystrix and call first level transactional function.

How can I get transaction event(commit, rollback)

I created a CMT based EJB. The EJB inserts a record into the database and then it executes another code(A) asynchronously. The ejb continues it's processing so the transaction can be committed or rolledback after asynchronous call.
In the code (A) I need to wait until the EJB's transaction committed or rolled back. Then read the record which the EJB inserted or skip next execution.
My question is that can I notified the EJB's transaction event or have to poll until I can read the record.
I'm working on the IBM WebSphere 7.0 (Java EE 5)
The only way to synchronize asynchronously invoked code with transaction events, as far as I know, is to use CDI events. In the code that runs inside the transaction you have to send a CDI event. You can configure the handler of the CDI event to run only on certain transaction outcomes - these handlers are called transactional observers.
I found this page from the JBoss docs that outline the syntax and general concept - see section 11.7
http://docs.jboss.org/weld/reference/latest/en-US/html/events.html
Basically it looks like this
public void refreshCategoryTree(#Observes(during = AFTER_SUCCESS) CategoryUpdateEvent event)
{// only called after the transaction committed successfully }
I don't know about WebSphere but since this is part of the CDI Spec I would assume it should work there as well. I once used this with JBoss and it worked for me. You can even have the handler run inside its own transaction if you want.

spring + struts2, inject DAO into external thread

I have a web application that uses Struts2 + Spring for the resource injection, basically my DAO. Now I would like to create a thread that periodically polls the database and, if needed, send email notifications to users.
I would like to know how I can implement this in a way that this thread can use my DAO. I haven't been able to manage Spring to inject it the way I've done it. So I would like to hear suggestions and see if someone can point me to the right way.
Right now I have a thread started by a ServletContextListener, that just creates a timer and schedules an action every 5 minutes. But I can't get this action to use my DAO. I don't have any need to use this structure, I'm open to using whichever solution works.
Thanks for your help!
Edit: As axtavt suggested, I used Spring task Execution Scheduling and it works perfectly, the thing is that my task gets injected with the DAO but then I get LazyInitializationException every time I try to access a property of my fetched objects, any suggestion on how to solve that??
Perhaps the best option is to use Spring's own scheduling support, see 25. Task Execution and Scheduling (if necessary - with Quartz, see 25.6 Using the OpenSymphony Quartz Scheduler). This apporach allows you to configure your scheduled action as Spring beans, so you can wire them with other beans such as DAO.
Alternatively, you can use the following to obtain any Spring bean in web application (for example, to obtain DAO from your thread):
WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean(...)

Resources