我们有一个订阅 ActiveMQ Classic 队列的消费者(C# 应用程序)。我们正在使用
AcknowledgementMode.Transactional
创建会话。
连接URI:
activemq:failover://(tcp://broker1.com:61780)?randomize=false&transport.maxReconnectAttempts=3&transport.reconnectDelay=3000&connection.prefetchPolicy.queuePrefetch=1
该应用程序有很多实例在运行,并且每个实例都运行良好。
在消费者应用程序中接收消息,该消息向代理发送 ack (
_session.Commit()
)。这个过程一直运行没有问题,直到最近我们的网络出现了一些间歇性故障。
在这种情况下,AMQ 代理会从方法
TransactionRolledBackException
抛出
_session.Commit()
这是完整的堆栈跟踪:
Apache.NMS.TransactionRolledBackException: Transaction completion in doubt due to failover. Forcing rollback of ID:qcyp-slack-03-64154-638666766860410819-1:3826:5
at Apache.NMS.ActiveMQ.Connection.SyncRequest(Command command, TimeSpan requestTimeout)
at Apache.NMS.ActiveMQ.TransactionContext.Commit()
at Apache.NMS.ActiveMQ.Session.DoCommit()
at MyCompany.ActiveMQ.ActiveMqClient.Commit()
at MyCompany.Core.Messaging.Pooling.AvailableMessageQueueClient.Commit()
此问题是间歇性的。根据我们对日志的研究和分析,我们发现,当我们得到这个
TransactionRolledBackException
时,代理回滚了事务,因此相同的消息将被传递给另一个消费者。
现在,我的问题是我们如何防止此类异常,或者如何使我们的应用程序对此类问题更具弹性?
完全防止事务回滚的唯一方法是确保操作环境永远不会出现任何问题(例如网络故障)并且您的应用程序永远不会出现任何错误(例如处理消息时崩溃)。
然而,这是一个完全不切实际的目标。总会有问题,事实上,这是最初创建交易的主要原因之一。事务回滚是一个功能,而不是一个错误。这是处理故障的一种优雅的方式,您的应用程序应该能够处理它。理论上,您的应用程序应该能够再次使用该消息并且不会受到任何不良影响。