从 EF 核心迁移进行前/后迁移以确保零停机时间

Hen*_*san 5 .net deployment high-availability entity-framework-migrations

我们的解决方案有 2 个网络服务器的生产设置,这两个网络服务器是负载平衡的,并连接到同一个数据库。

我们使用 Octopus 部署,并执行滚动部署,我们在负载均衡器中禁用正在更新的网络服务器。

我们首先使用实体​​框架代码迁移,并在部署时运行 dotnet ef migrations script,以生成我们可以对数据库执行的 SQL 脚本。这是我们斗争的开始。

发生的迁移发生了重大更改,导致仍然在线的网络服务器由于数据库不匹配而失败。

所以我们需要在迁移前和迁移后进行

  • 在部署之前运行预迁移,这会将数据库置于应用程序旧版本和新版本一起工作的状态。
  • 部署后运行迁移后,清理数据库。

根据我拥有的 sql 脚本,我一直无法找到可以为我创建这些预迁移的工具,我开始认为这是一个梦想,这可能吗?如果没有,人们在他们的部署管道中做什么?

我看过 Liquibase、DbUp、Roundhouse,但它们都没有提供我想要的功能。

小智 0

您可以尝试使用 DbUp,我们这样做并取得了相当好的结果,尽管这确实意味着我们要手动创建运行的前后脚本。每个 .sql 文件都以 Pre_ 或 Post_ 作为起始名称,并且将它们捆绑到一个文件夹中以进行更改。

然后我们有一个单独的项目,它构建到一个 .exe 中,我们可以将 pre 或 post 作为参数传递给它。所以我们的部署是:

运行前置脚本 运行部署 运行后置脚本

这还允许正在运行的命令有一个明显更长的超时,因为我们知道我们不会造成任何中断(即有时添加新索引可能需要几分钟)

static void PerformUpgrade(string dbConnection, string prePostDeployOption)
        {
            // DbUp is a .NET library that helps you to deploy changes to SQL Server databases. It tracks which SQL scripts have been run already,
            // and runs the change scripts that are needed to get your database up to date.

            // If you want your application to create the database for you, add:
            // EnsureDatabase.For.SqlDatabase(dbConnection);

            // Upgrade database if required
            var upgrader = DeployChanges.To.SqlDatabase(dbConnection)

                // Retrieves upgrade scripts or IScript code upgrade scripts embedded in an assembly:
                // - .sql files where 'Build Action' is set to 'Embedded resource'
                // - Code inheriting from IScript which returns SQL string to run
                .WithScriptsAndCodeEmbeddedInAssembly(
                    Assembly.GetExecutingAssembly(),
                    (string s) =>
                        // Only run SQL and code scripts beginning with "Pre_" or "Post_", depending on selection made
                        s.Contains($".{prePostDeployOption}_", System.StringComparison.CurrentCultureIgnoreCase)
                )

                // Allow for a longer timeout on long running scripts
                .WithExecutionTimeout(TimeSpan.FromMinutes(10))

                // By default, DbUp adds a table to your SQL Server database called SchemaVersions, which tracks the scripts that have already been executed.
                // Before running, DbUp checks this table to work out which scripts should be skipped. After running, it inserts journal records to record
                // the scripts that have been run.
                .JournalToSqlTable("dbo", "_DbMigrations")

                // By default, the output of the scripts run by DbUp do not show up in the logs. To also display the script output (e.g. text displayed by PRINT statements in SQL Server), use this method.

                .LogScriptOutput()

                .Build();

            // Performs upgrade if necessary
            var result = upgrader.PerformUpgrade();

            if (result.Successful)
            {
                // Always outputs task summary to Octopus Deploy even if no scripts were run (i.e. "Ran 0 scripts")
                result.WriteExecutedScriptsToOctopusTaskSummary();
            }
        }
Run Code Online (Sandbox Code Playgroud)