在与Entity Framework Core 3.0结合的TransactionScope中征集Rebus,而不需要两阶段提交。

问题描述 投票:1回答:1

我正在使用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,因为Entity Framework和Rebus将使用相同的关系数据库实例。

调用 EnlistRebus 是在Rebus.TransactionScopes包中,不知道使用的是什么传输实现,可能会做安全的事情。

有没有其他方法可以同时进行数据库操作和Rebus事务性发送而不需要2阶段提交?当然,我可以用一个单独的表来存储我的待处理消息,从 SaveChanges 并让一个单独的工作者从该表中提取并使用Rebus发送消息。我怀疑这种方法是最稳妥和直接的。

我使用的是Rebus 6.3.0、Rebus.PostgreAql 7.1.0、Rebus.TransactionScopes 6.0.0、Npgsql 4.1.3.1、Npgsql.EntityframeworkCore.PostgreSQL 3.1.4和EF Core 3.1.4。

postgresql entity-framework-core rebus
1个回答
1
投票

Rebus.PostgreSQL在没有Rebus.TransactionScopes的情况下,实际上会自己加入到环境事务中。

在Rebus.PostgreSQL repo中,我看到有一个PR似乎可以解决我的问题。引用PR的内容 https:/github.comrebus-orgRebus.PostgreSqlpull14。:

我先试着去找 https:/github.comrebus-orgRebus.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会在内部重用同一个连接,避免升级到一个完整的分布式事务。

© www.soinside.com 2019 - 2024. All rights reserved.