I am currently playing around with guava's eventbus in spring and while the general functionality is working fine so far i came across the following problem:
When a user want's to change data on a "Line" entity this is handled as usual in a backend service. In this service the data will be persisted via JPA first and after that I create a "NotificationEvent" with a reference to the changed entity. Via the EventBus I send the reference of the line to all subscribers.
public void notifyUI(String lineId) {
EventBus eventBus = getClientEventBus();
eventBus.post(new LineNotificationEvent(lineId));
}
the eventbus itself is created simply using new EventBus() in the background.
now in this case my subscribers are on the frontend side, outside of the #Transactional realm. so when I change my data, post the event and let the subscribers get all necessary updates from the database the actual transaction is not committed yet, which makes the subscribers fetch the old data.
the only quick fix i can think of is handling it asynchronously and wait for a second or two. But is there another way to post the events using guava AFTER the transaction has been committed?
I don't think guava is "aware" of spring at all, and in particular not with its "#Transactional" stuff.
So you need a creative solution here. One solution I can think about is to move this code to the place where you're sure that the transaction has finished.
One way to achieve that is using TransactionSyncrhonizationManager:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
// do what you want to do after commit
// in this case call the notifyUI method
}
});
Note, that if the transaction fails (rolls back) the method won't be called, in this case you'll probably need afterCompletion method. See documentation
Another possible approach is refactoring your application to something like this:
#Service
public class NonTransactionalService {
#Autowired
private ExistingService existing;
public void entryPoint() {
String lineId = existing.invokeInTransaction(...);
// now you know for sure that the transaction has been committed
notifyUI(lineId);
}
}
#Service
public class ExistingService {
#Transactional
public String invokeInTransaction(...) {
// do your stuff that you've done before
}
}
One last thing I would like to mention here, is that Spring itself provides an events mechanism, that you might use instead of guava's one.
See this tutorial for example
Related
I struggle to find and implement the best practise for the following problem: where is the best location to raise create domain event (the event that notifies for the creation of an aggregate). For example if we have Order aggregate in our bounded context we would like to notifie all interested parties when order is create. The event could be OrderCreatedEvent.
What I tried in first place is to raise this event in the constructor (I have a collection of domain events in each aggregate). This way it is okay only when we create the order. Because when we would like to do anything with this aggregate in the future we are going to create new instance of it through the constructor. Then OrderCreatedEvent will be raised again but it is not true.
However, I thought it would be okey to raise the event in the application layer but it is an anti-pattern (the domain events should live only in the domain). Maybe to have a method Create that will just add the OrderCreatedEvent to its domain events list and call it in the application layer when order is created is an option.
Interesting fact I found on the internet is that it is an anti-pattern to raise domain events in the contructor which means the last described option (to have Create method) would be the best approach.
I am using Spring Boot for the application and MapStruct for the mapper that maps the database/repository Entity to the domain model aggregate. Also, tried to find a way to create a mapper that is going to skip the contructor of the target class but as all properties of the Order aggregate are private seems impossible.
Usually constructor are used only to make assignations on object's fields. This is not the right place to trigger behaviours, especially when they throw exceptions or have side effects
DDD theorists (from Eric Evans onwards) suggest implementing factories for aggregates creation. A factory method, for example, can invoke aggregate constructor (and wire up the aggregate with child domain objects as well) and also register an event.
Publishing events from the application layer is not an anti-pattern per se. Application services can depend from the domain events publisher, the important thing is that it's not application layer to decide which event to send
To summarize, with a stack like Java Spring Boot and domain events support, your code could look like
public class MyAggregate extends AbstractAggregateRoot {
public static MyAggregate create() {
MyAggregate created = new MyAggregate();
created.registerEvent(new MyAggregateCreated());
return created;
}
}
public class MyApplicationService {
#Autowired private MyAggregateRepository repository;
public void createAnAggregate() {
repository.save(MyAggregate.create());
}
}
notice that event publishing happens automagically after calling repository.save(). The downside here is that, when you use db-generated identifiers, aggregate id is not avaliable in the event payload since it's associated after persisting the aggregate. If i will change the application service code like that:
public class MyApplicationService {
#Autowired private MyAggregateRepository repository;
#Autowired private ApplicationEventPublisher publisher;
public void createAnAggregate() {
repository.save(MyAggregate.create()).domainEvents().forEach(evt -> {
publisher.publish(evt);
});
}
}
Application layer is in charge to decide what to do to fulfill this workflow (create an aggregate, persist it and send some event) but all the steps happen transparently. I can add a new property to the aggregate root, change DBMS or change event contract, this won't change these lines of code. Application layer decides what to do and domain layer decides how to do it. Factories are part of the domain layer, events are a transient part of the aggregate state and the publishing part is transparent from domain standpoint
Check out this question!
Is it safe to publish Domain Event before persisting the Aggregate?.
However, I thought it would be okey to raise the event in the application layer but it is an anti-pattern (the domain events should live only in the domain). - Domain events live in Domain layer, but Application layer references Domain layer and can easily emit domain events.
i have a spring boot maven multi module project with axon 4.4.2, the hierarchy of project is as below:
application
--core
--command-side
----command-side-axon
----command-side-rest
--query--side
----query-side-persistence
----query-side-rest
i have an example of create a new catalog as below, when i send a request from command-side-rest, it always returns an id as response, even if the query-side-persistence crashes and the data not is saved in the database. How can i handle transactions in this case ? I want when the query-side-persistence crashes the event does not get saved in the event base and it throws an exception.
command-side-rest
#PostMapping
public String save(#RequestBody Catalog catalog) {
return (String) commandGateway.sendAndWait(new CreateCatalogCommand(catalog));
}
command-side-axon
#CommandHandler
public void handle(CreateCatalogCommand cmd) {
apply(new CatalogCreatedEvent(cmd.externalId, cmd.name));
}
#EventSourcingHandler
#Order(1)
public void on(CatalogCreatedEvent evt) {
this.externalId = evt.externalId;
}
query-side-persistence
#EventHandler
#Transactional(propagation = Propagation.REQUIRED)
#Order(2)
public void on(CatalogCreatedEvent event) {}
I think I can give you some information on the matter, concerning your main question:
I want when the query-side-persistence crashes the event does not get saved in the event base and it throws an exception.
Well, that essentially means you do not want to use CQRS at all. What CQRS stands for is the segregation of your Command Model (e.g. the Aggregate handling the command and publishing the event) and the Query Models (e.g. the classes handling events which updates your models).
Segregating these two gives you the benefit that you can optimize your models for both scenarios. Added, the request to perform an operation, aka the command, is no longer influenced on whether the subsequent event actually can update a query model. On top of that, it shouldn't if you are doing CQRS! Having this exact segregation means you can recreate your Query Models whenever you need, entirely separated from performing the commands.
Thus essentially, your Event Store because the single model you can base all models from, independent from another. This is why using events when going for CQRS works so nicely with Event Sourcing (which states to recreate your Command Model based on the events it has published).
So, my recommendation? I would embrace the fact that if event handling to update your query model fails, that the event still has happened. It essentially didn't change the fact your system has made the decision to publish that event, so let it be so.
If you do want to have your Command Model and Query Model in a single transaction, you could still achieve this by only using the SubscribingEventProcessor in Axon. Again though, I would discuss with your team/business whether that is really what you need.
Check out some of the posts on the "learning" page of AxonIQ to have a feel why CQRS, DDD and Event Sourcing can be beneficial for you.
Hope this sheds some light on the situation Aymen!
I want to implement simple chat but store them only during server work. I don't want to store them in database, just like in List or Map. How to?
This solution works for "Simple" chat as you explained.
There isn't much information on how you had built this before so I'm just going to explain how to have an Application scoped bean that can be injected into other beans to handle storing chat.
You can configure a Service to store this information.
ChatHistoryService.java
#Service
#Scope("application")//This is the key this will keep the chatHistory alive for the length of the running application(As long as you don't have multiple instances deployed(But as you said it's simple so it shouldn't)
public class ChatHistoryService {
List<String> chatHistory = new LinkedList<>();//Use LinkedList to maintain order of input
public void storeChatMessage(String chatString) {
chatHistory.add(chatString);
}
public List<String> getChatHistory() {
//I would highly suggest creating a defensive copy of the chat here so it can't be modified.
return Collections.unmodifiableList(chatHistory);
}
}
YourChatController.java
#Controller
public class YourChatController {
#Autowired
ChatHistoryService historyService;
...I'm assuming you already have chat logic but you aren't storing the chat here is where that would go
...When chat comes in call historyService.storeChatMessage(chatMessage);
...When you want your chat call historyService.getChatHistory();
}
Once again keep in mind that this really only works for a simple application. If it's distributed there will be different chat histories per instance of the application at that point you could look into a distributed cache.
In any case don't go beyond simple with this implementation.
If you look here it will give you an idea of several caches that work with spring boot.
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache
I am wondering if there is a way to wrap all argument resolvers like for #PathVariables or #ModelAttributes into one single transaction? We are already using the OEMIV filter but spring/hibernate is spawning too many transactions (one per select if they are not wrapped within a service class which is be the case in pathvariable resolvers for example).
While the system is still pretty fast I think this is not necessary and neither consistent with the rest of the architecture.
Let me explain:
Let's assume that I have a request mapping including two entities and the conversion is based on a StringToEntityConverter
The actual URL would be like this if we support GET: http://localhost/app/link/User_231/Item_324
#RequestMapping("/link/{user}/{item}", method="POST")
public String linkUserAndItem(#PathVariable("user") User user, #PathVariable("item") Item item) {
userService.addItem(user, item);
return "linked";
}
#Converter
// simplified
public Object convert(String classAndId) {
return entityManager.find(getClass(classAndId), getId(classAndId));
}
The UserService.addItem() method is transactional so there is no issue here.
BUT:
The entity converter is resolving the User and the Item against the database before the call to the Controller, thus creating two selects, each running in it's own transaction. Then we have #ModelAttribute methods which might also issue some selects again and each will spawn a transaction.
And this is what I would like to change. I would like to create ONE readonly Transaction
I was not able to find any way to intercept/listen/etc... by the means of Spring.
First I wanted to override the RequestMappingHandlerAdapter but the resolver calls are well "hidden" inside the invokeHandleMethod method...
The ModelFactory is not a spring bean, so i cannot write an interceptor either.
So currently I only see a way by completely replacing the RequestMappingHandlerAdapter, but I would really like to avoid that.
And ideas?
This seems like a design failure to me. OEMIV is usually a sign that you're doing it wrong™.
Instead, do:
#RequestMapping("/link/User_{userId}/Item_{itemId}", method="POST")
public String linkUserAndItem(#PathVariable("userId") Long userId,
#PathVariable("itemId") Long itemId) {
userService.addItem(userId, itemId);
return "linked";
}
Where your service layer takes care of fetching and manipulating the entities. This logic doesn't belong in the controller.
I'm a beginner in hibernate 4 & Spring 3.2 stuffs.
I have read some tutorials and discussion on stack but i don't find a clear answer to my questions. And i think the best way to understand is to ask and share knowledges !
Here we go!
So you create each time a Pojo, a Dao , a Service class, with methods annotated transactionnal. That's ok. I'm using Sessionfactory to handle my transaction. I'm looking for good practices.
1- If you want to use Delete Method and Save Method from the same Service, how will you do to make it works in a same transaction. When i look at the log, each method are executed in different transactions.
This SampleServiceImpl:
#Transactional
public void save(Sample sample){
sampleDao.save(sample);
}
#Transactional
public void delete(Sample sample){
sampleDao.delete(sample);
}
// A solution could be that , but not very clean...there should be an another way, no?
#Transactional
public void action(Sample sample){
sampleDao.save(sample);
sampleDao.delete(sample);
}
2- If you want to use Delete Method and Save Method from different Services class, how will you do to make it works in a same transaction. Because each method in each service class is handled by a Transactionnal annotation. Do you create a global Service calling all subservice in one method annoted Transactional
SampleServiceImpl:
#Transactional
public void save(Sample sample){
sampleDao.save(sample);
}
ParcicipantServiceImpl
#Transactional
public void save(Participant participant){
participantDao.save(participant);
}
// A solution could be that , but not very clean...there should be an another way, no?
GlobalServiceImpl
#Transactional
public void save(Participant participant,Sample sample){
participantDao.save(participant);
sampleDao.save(sample);
}
3- And the last question but not the least .If you want to use several Methods from severals service in one global transaction. Imagine you want to fill up 5 or more table in one execution of a standalone program. How is it possible because each Service to have his proper transactional method, so each time you called this method, there is a transaction.
a- I have successfully arrive to fill up two tables in a sample transaction using Mkyong tutorial and cascade property in the mapping. So i see how to make it works for one table directly joined to one another or more tables.
b- But if you have a 3 tables Participant -> Samples -> Derived Products. How will you fill up the three tables in a same transaction.
I don't know if i'm clear. But i would appreciated some help or example on that from advanced users.
Thanks a lot for you time.
Your solution is fine, maybe this works if you want to using nested transactional methods(note I saw this solution couple days ago and didn't test it):
< tx:annotation-driven mode="aspectj" / >
< context:load-time-weaver aspectj-weaving="on"/ >
#Transactional
public void action(Sample sample){
save(sample);
delete(sample);
}
Transaction should propagate.
GlobalServiceImpl
#Transactional
public void save(Participant participant,Sample sample){
participantDao.save(participant);
sampleServiceImpl.save(sample);
}
The approch you are following is cleaner approch,
ServiceOpjects are ment to contain business logic. Hence they will always manuplate through data objects.
What we do in practise is create a another layer that uses dataObjects and and other functional call of same layer. Then this all business layer is called via service layer having annotation #transactional.
Can you please mention why you think this approch is dirty??