Rails 大家一般线上环境的 migration 在什么时候执行?

willx · 2025年04月17日 · 最后由 Rei 回复于 2025年04月18日 · 280 次阅读

kamal 的部署流程中好像也没有单独提到 db:migrate 这种操作的执行时机,特别是在多台机器分布式部署的时候,官方文档里找了一圈也没看到有什么最佳实践。

通常本地环境开发调试完毕之后,大家会在什么地方对线上环境做 migrate 呢?

上线发版的时候啊

在 Rails 默认生成的项目中在,在 bin/docker-entrypoint 文件中,容器启动时,自动执行 migrate 的:

# If running the rails server then create or migrate existing database
if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then
  ./bin/rails db:prepare
fi
qichunren 回复

但是分布式部署上多台机器会执行多次吧,可能会出问题

tu6ge 回复

改了一下描述,不是说这个时间,而是说部署的时候,rails 默认是启动容器的时候运行 migrate,分布式部署多台机器就会运行多次,如果凑巧同时运行了是不是存在风险的

willx 回复

migration 过程有数据库锁,不会重复执行。 https://github.com/rails/rails/pull/22122

Rei 回复

rails/activerecord/lib/active_record/migration.rb

看源码这里如果强锁失败会报错的,不会影响容器启动吗?

willx 回复

我没验证过,也许 entrypoint 里面失败不影响启动?

willx 回复

我试过,确实会抛异常。但 entrypoint.sh 中如果不写 set -e 的话是可以忽略错误的,所以并不影响执行

spike76 回复

不行吧,看源码抢锁失败会直接报错,如果把默认的 -e 删了,那不是其他机器 migrate 还在进行,这台机器的新代码就跑起来了。

把数据库变更从应用启动过程中解耦出来,单独跑 db:migrate,跑完再上线业务代码,做好旧代码对于数据库新结构的兼容

willx 回复

默认 entrypoint 是带 -e 的,所以除了执行迁移的容器其他容器会启动失败。然后 kamal 会隔几秒重试启动,直到超过重试次数。容器启动后健康检查通过才会替换旧容器。

如果有超长时间的迁移,可以关注维护模式这个新功能(未发布) https://github.com/basecamp/kamal/pull/1497

需要 登录 后方可回复, 如果你还没有账号请 注册新账号