问题描述
我正在尝试使用服务将项目保留在DB中,并为后续服务触发JMS消息以提取保留的项目,以便它可以处理相同的项目。此特定操作在单个事务中发生。但是由于种族状况,有时第二服务无法获取相应的项目,因为该项目尚未持久。
I am trying to persist an item in DB using a service and firing a JMS message for the subsequent service to pick up the persisted item so that it can process the same. This particular operations happens in a single transaction. But due to race condition at times, the second service is not able to fetch the respective item as its not yet persisted.
我的用例非常普遍,各种论坛中都有很多与此相关的讨论。解决此问题的一种方法是使用CDI事件。我尝试了同样的方法,可以解决部分问题。伪代码如下:
My use case is very common and there are so many discussions related to this in various forums. One solution for this issue is to use CDI events. I tried the same and could solve a part of the problem. The pseudo code is as follows:
@Inject
@Transaction
private Event<Item> itemEvent;
public void handleItem(Item item) {
//code to persist the item
itemEvent.fire(item);
}
@Asynchronous
public void observeAfterTransactionCompletion(@Observes(during = TransactionPhase.AFTER_SUCCESS) @Transaction Item item) {
//code to send JMS message to the second service
}
我唯一的问题是持久性成功时&事件被触发,并且如果Jboss服务器宕机,则在观察者即将开始处理事件之前,不会通知第二个服务,因为JMS消息将不会发送。
My only issue is when the persistence is successful & event is fired and just before the observer starts processing the event if the Jboss server goes down, the second service will not be notified as the JMS message wont be send.
将CDI容器可以在内部处理这种情况,以便始终调用该事件?是否会在服务器启动时通知观察者自动启动?如果没有,我该如何处理这种情况,以便我的方法是万无一失的?
Will the CDI container can internally handle this scenario so that the event will always be invoked? Will the observer be notified on server start automatically? If not, How do I handle this scenario so that my approach is fool proof?
注意::我已经尝试了第二种服务中的重试方法,直到消息可用。另外,将事件保留在另一个队列中是一种替代方法,这似乎非常乏味。寻找一种聪明的方法。
NOTE: I have already tried out the retry approach in second service till the message is available. Also persisting the event in an other queue is an alternate approach which seems very tedious. Looking for a smart approach.
更新:我的初始代码是这样编写的,即持久性和消息传递是在单个事务中进行的。但这导致第二个服务消耗了消息,甚至没有第一个服务持久性就成功导致了错误,因为第二个服务找不到所需的数据,这些数据尚未被持久化。
UPDATE: My initial code was written in such a way that the persistence and messaging was in single transaction. But that resulted in message consumption by second service before even first service persistence is successful resulting in error as second service could not find the required data which is yet to be persisted.
更新2:初始方法伪代码如下:
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void processMessage(){
//将数据持久保存到DB
的代码//将JMS消息发布给消费者的代码
}
UPDATE 2: Intial approach pseudo code as follows:@TransactionAttribute(TransactionAttributeType.REQUIRED)public void processMessage() { // code to persist data to DB // code to publish JMS message to the consumer}
即使通过使用xa-datasouce和xa-connection工厂,问题仍然存在。
Even by using xa-datasouce and xa-connection factory, the issue still exists.
推荐答案
CDI事件不是持久性的,因此它们不会重新出现。
CDI events are not persistent and hence they dont get re-triggered after server restart.
最后,我们最终通过在发布消息之前使用DB持久性解决了该问题,并拆分了持久性&发布为两个不同的交易。但是,如果发生消息发布错误或服务器在消息发布提交之前重新启动,我们需要自己处理消息重复。
Finally we ended up resolving the issue by using DB persistence before publishing the message and splitting up persistence & publishing into two different transactions. However we need to handle message duplication ourselves in case of message publishing errors or server restarts before message publishing commits.
这篇关于服务器崩溃和重新启动时的CDI事件观察器处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!