【发布时间】:2018-04-12 12:57:13
【问题描述】:
有一个 .NET 4.7 WebAPI 应用程序使用实体框架与 SQL Server 一起工作,并通过 MSMQ 传输托管 NServiceBus 端点。
可以通过控制器操作来描述简化的工作流程:
[HttpPost]
public async Task<IHttpActionResult> SendDebugCommand()
{
var sample = new Sample
{
State = SampleState.Initial,
};
_dataContext.Set<Sample>().Add(sample);
await _dataContext.SaveChangesAsync();
sample.State = SampleState.Queueing;
var options = new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
};
using (var scope = new TransactionScope(TransactionScopeOption.Required, options, TransactionScopeAsyncFlowOption.Enabled))
{
await _dataContext.SaveChangesAsync();
await _messageSession.Send(new DebugCommand {SampleId = sample.Id});
scope.Complete();
}
_logger.OnCreated(sample);
return Ok();
}
还有DebugCommand 处理程序,即发送到同一个 NServiceBus 端点:
public async Task Handle(DebugCommand message, IMessageHandlerContext context)
{
var sample = await _dataContext.Set<Sample>().FindAsync(message.SampleId);
if (sample == null)
{
_logger.OnNotFound(message.SampleId);
return;
}
if (sample.State != SampleState.Queueing)
{
_logger.OnUnexpectedState(sample, SampleState.Queueing);
return;
}
// Some work being done
sample.State = SampleState.Processed;
await _dataContext.SaveChangesAsync();
_logger.OnHandled(sample);
}
有时,消息处理程序从数据库中检索Sample,其状态仍为Initial,而不是预期的Queueing。这意味着在控制器操作中启动的分布式事务尚未完全完成。日志文件中的时间戳也证实了这一点。
“有时”很少发生,在较重的负载和网络延迟可能会受到影响。本地数据库无法重现问题,但远程数据库可以轻松重现。
我检查了 DTC 配置。我确实检查了分布式事务的升级。此外,如果未调用 scope.Complete(),则不会发生 DB 更新,也不会发生消息发送。
当事务范围完成并处置后,直觉上我希望 DB 和 MSMQ 在执行一条进一步的指令之前都已解决。
我找不到问题的明确答案:
- 这是 DTC 的工作方式吗?交易双方都进行提交,而完成没有报告给协调者,这是正常的吗?
- 如果是,是否意味着我应该通过改变程序逻辑来克服此类事件?
- 我是否以某种方式滥用事务?什么是正确的方法?
【问题讨论】:
-
这里有类似的问题:stackoverflow.com/q/37463562/5311735
-
@Evk,谢谢!这有助于并证实了我对现实的理解。
标签: c# sql-server nservicebus msmq msdtc