嗨,我有这段代码
SendMessageToMyQueue();
UpdateStatusInDbThatMessageWasSent();
有时在状态更新之前处理消息,我想避免。
我的问题是,如果我用这样的事务包装那两行:
using(var tr = new TransactionScope())
{
SendMessageToMyQueue();
UpdateStatusInDbThatMessageWasSent();
tr.Compleate();
}
将保证MyQueue
创建一个锁,并且在UpdateStatusInDbThatMessageWasSent
更新状态之前不会释放此锁定?
如果我添加带有回滚的try catch并且更新状态失败,该消息是否会从MyQueue
中删除?
答案 0 :(得分:1)
没有锁定队列这样的东西。但是,如果满足以下条件,则将以事务方式处理该消息。通过事务方式,我的意思是如果抛出未处理的异常,消息将返回到队列。实现这一目标的条件是:
您的数据库可以登记并参与分布式事务。不是每个数据库都有。某些文档数据库没有(对于MongoDB)或粗略(对于RavenDB)支持DTC。
您的传输还支持分布式事务。如果您使用代理类型传输,SQL Server传输是您最好的选择,并且在总线类型传输上MSMQ是一个不错的选择。 Azure ServiceBus或RabbitMQ等传输的事务支持非常有限,不支持分布式事务。
您需要运行已配置并运行的分布式事务处理协调器服务。
另外两件事需要注意:
如果您使用缺乏DTC支持的运输怎么办?大多数情况下,如果您可以将系统设计为idempotent,那么您会感觉更好。 NServiceBus的Outbox功能允许您在一定程度上模拟DTC。
当从队列中挑选消息,处理消息并由于异常而返回到队列时,它可能最终位于队列中的不同位置。在设计基于消息的架构时,您需要design for messages arriving out of order。
综上所述,exactly-once delivery guarantees始终是一个热门话题并且存在争议。