在与实体框架核心 3.0 结合使用的事务范围中登记 Rebus,而无需两阶段提交



我正在使用Entity Framework Core和PostgreSQL。我想重写 DbContext 中的 SaveChanges 以提交 EF 更改,并在同一数据库事务中使用 Rebus 发送消息。该计划也是使用 PostgreSQL 进行传输等,但我在使用以下代码仅在事务范围内注册 Rebus 时遇到了麻烦。

public override int SaveChanges()
{
using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
tx.EnlistRebus();
var result = base.SaveChanges();
//TODO: _bus.Send("something happened");
tx.Complete();
return result;
}
}

运行上述结果为PostgresException: 55000: prepared transactions are disabled,这是真的,因为我的 PostgreSQL 配置尚未启用它。我的问题是为什么 Rebus 需要在这里导致 2 阶段提交。也许我错过了一些东西,尽管我希望不需要 2PC,因为实体框架和 Rebus 都将使用相同的关系数据库实例。

EnlistRebus的调用位于 Rebus.TransactionScopes 包中,并且不知道正在使用哪种传输实现,并且可能会执行安全操作。

有没有另一种方法可以在没有两阶段提交的情况下同时执行数据库操作和 Rebus 事务发送?当然,我可以使用单独的表来存储来自SaveChanges的待处理消息,并从该表中拉取单独的工作线程并使用 Rebus 发送消息。我怀疑这种方法是最可靠和直接的。

我正在使用Rebus 6.3.0,Rebus.PostgreAql7.1.0,Rebus.TransactionScopes 6.0.0,Npgsql 4.1.3.1,Npgsql.EntityframeworkCore.PostgreSQL 3.1.4和EF Core 3.1.4。

Rebus.PostgreSQL 实际上会在没有 Rebus.TransactionScopes 的情况下自行注册环境事务。

查看Rebus.PostgreSQL存储库,我看到有一个PR似乎可以解决我的问题。引用公关在 https://github.com/rebus-org/Rebus.PostgreSql/pull/14:

我首先尝试让 https://github.com/rebus-org/Rebus.TransactionScopes 工作,但这似乎没有使用 postgresql 传输做任何事情。

为了验证它确实在环境事务中执行消息发布,我进行了以下修改:

public override int SaveChanges()
{
using (var tx = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, 
TransactionScopeAsyncFlowOption.Enabled))
{
var result = base.SaveChanges();
_bus.Send(new MyMessage { CurrentDateTime = DateTime.Now}).Wait();
if (ShouldCrash)
{
throw new ArgumentException();
}
tx.Complete();
return result;
}
}

如果ShouldCrash设置为true,则不会发布任何消息,也不会对实体进行任何更改。如果ShouldCrash设置为false则同时执行消息发布和实体更改。

我认为这是有效的,因为 Npgsql 文档中的以下内容:

请注意,如果在环境事务中打开和关闭与同一数据库的连接,而没有同时打开两个连接,Npgsql 将在内部重用同一连接,从而避免升级到成熟的分布式事务。

相关内容

  • 没有找到相关文章

最新更新