如何在Rails部署过程中处理迁移失败?

huangapple go评论101阅读模式
英文:

How to deal with failed migrations during deployment in Rails?

问题

为了随着时间的推移演变数据库架构,我们需要进行数据库迁移。Rails为我们提供了很好的功能来实现这一点。正如我们所知,Rails中的每个迁移都包含在一个DDL事务中(至少对于Postgres来说)。这意味着如果某个迁移在中途失败,那么与该迁移相关的所有更改都将被回滚。但我注意到,如果我们有多个迁移,其中一个失败了,那么之前的迁移将不会被回滚。这在生产部署方面是一个问题,因为新的一部分迁移可能只完成了一部分。

让我们假设我们有5个新的迁移,我们想要部署到生产环境中。

migration_1.rb
migration_2.rb
migration_3.rb
migration_4.rb
migration_5.rb

如果例如在 migration_4.rb 中发生错误,那么之前的所有迁移(migration_1.rbmigration_2.rbmigration_3.rb)将不会被回滚。

我该如何处理这种情况?

我有一个想法,可以取消代码部署并通过类似以下方式回滚之前的迁移:

rails db:rollback STEP=n # n - 成功通过的迁移数量

但然后我又有另一个问题 - 如果在回滚过程中发生错误怎么办?

英文:

To evolve a DB schema over time we need to do DB migrations. Rails provide us with great functionality to do that. As we know, each migration in Rails is wrapped in a DDL transaction (at least for Postgres). It means that if some migration is failed in halfway then all changes related to this migration will be rolled back. But, I've noticed that if we have more than one migration and one of them fails then previous migrations will not have been rolled back. And it is a problem in terms of production deployment since a new portion of migrations can be done partially.

Let's imagine we have 5 new migrations that we want to deploy into production.

migration_1.rb
migration_2.rb
migration_3.rb
migration_4.rb
migration_5.rb

If an error occurs for example on migration_4.rb then all previous migrations (migration_1.rb, migration_2.rb, migration_3.rb) will not have been rolled back.

How should I handle this situation?

I have an idea to cancel code deployment and rollback previous migrations by something like this

rails db:rollback STEP=n # n - number of migrations that managed to pass successfully

But then I have another question - what if an error occurs during rolling back?

答案1

得分: 2

我建议的最佳实践是:每次部署只进行一次迁移。迁移在一个事务中运行,所

英文:

The best practice I'd recommend: Only have one migration per deploy. Migrations run in a transaction, so if a single one fails, no harm done, assuming the deploy as a whole fails with it (so you don't end up deploying code changes that rely on the failed migration).

But if one succeeds and the next one fails, your database will end up in a state that you didn't intend, and you will have to manually roll back.

If your multiple migrations are related to each other and need to be deployed as one, just refactor them into a single migration file. If they belong to separate features that can be deployed individually, do that instead.

Regarding rollback failures - your migrations should always be able to roll back, and this should be part of your development process. If you migrate data, make sure to migrate it back in the down version, for example.

An easy way to test this is using db:migrate:redo locally. It's good practice to always to that before committing a migration.

huangapple
  • 本文由 发表于 2023年8月10日 18:52:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875043.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定