我正在尝试使用服务将一个项目持久保存在数据库中,并为后续服务触发 JMS 消息以获取持久保存的项目,以便它可以处理相同的项目。此特定操作发生在单个事务中。但由于有时存在竞争条件,第二个服务无法获取相应的项目,因为它尚未持久化。
我的用例非常常见,并且在各个论坛中有很多与此相关的讨论。此问题的一种解决方案是使用 CDI 事件。我也尝试过,并且可以解决部分问题。伪代码如下:
@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 消息不会发送。
CDI 容器是否可以在内部处理这种情况,以便始终调用该事件?服务器自动启动时观察者会收到通知吗?如果不是,我该如何处理这种情况,以便我的方法万无一失?
NOTE:我已经在第二个服务中尝试了重试方法,直到消息可用。将事件保留在其他队列中也是一种替代方法,这看起来非常乏味。寻找一种聪明的方法。
UPDATE:我最初的代码是以这样的方式编写的:持久性和消息传递位于单个事务中。但这导致第二个服务在第一个服务持久化成功之前就消耗了消息,从而导致错误,因为第二个服务无法找到尚未持久化的所需数据。
更新2:初始方法伪代码如下:@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void processMessage() {
// code to persist data to DB
// code to publish JMS message to the consumer
}
即使使用 xa-datasource 和 xa-connection 工厂,问题仍然存在。