我正在尝试使用Spring-AMQP的Transactionnal RabbitMQ通道,但我想实际上吞下Exceptions来记录它们并能够恢复它们。
使用channelTransacted = true强制Channel也加入当前的transactionManager(在我的情况下是Hibernate),这会导致提交异常从@Transactionnal边界重新抛出,导致上层失败而无法捕获它并记录下来。
我还尝试手动将发布附加到事务处,因此只有在提交成功后才会执行:
public void publishFailSafeAfterSuccessfulTransaction(final String routingKey, final String message) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
try {
rabbitTemplate.convertAndSend(routingKey, message);
} catch (Exception exception) {
logger.error("Error while publishing message to RabbitMQ ");
}
}
});
以这种方式使用:
Entity entity = save(entity);
publishFailSafeAfterSuccessfulTransaction("routingkey", "Entity was updated");
但在这种情况下,我不能使用channelTransacted = true,因为它会将registeringSynchronization嵌套在另一个registeringSynchronization中,并且根本无法调用...
有没有办法实现这一目标?
更新:理想情况下,我想要覆盖ConnectionFactoryUtils类中使用的RabbitResourceSynchronization,但它是一个没有工厂实例化的私有类
TransactionSynchronizationManager.registerSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched));
答案 0 :(得分:1)
我实施的解决方案是在提交主事务后在新事务中进行发布。
第一个电话:
Entity entity = save(entity);
publishFailSafeAfterSuccessfulTransaction("routingkey", "Entity was updated");
此方法注册在主要事务提交后进行发布。
public void publishFailSafeAfterSuccessfulTransaction(final String routingKey, final String event) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
try {
publishFailSafe(routingKey, event);
} catch (Exception exception) {
//Do some recovering
}
}
});
}
主要交易提交后,这个将进行发布。当通道被处理时,它将在提交新事务时提交消息,并且仅在该事务中失败并且错误将在先前方法中捕获。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void publishFailSafe(String routingKey, String event) {
try {
rabbitTemplate.convertAndSend(routingKey.getRoutingKey(), event);
} catch (Exception exception) {
//Do some recovering
}
}