You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在Heroku上无停机执行Rake任务与数据库迁移的方案咨询

嘿,咱们来逐个拆解你的问题,帮你理清这个部署方案的可行性和注意事项~

1. 你的方案是否可行?

方向是对的,但有个关键细节需要调整:别在release脚本里用heroku run rake my_rake_task

Heroku的release phase本身就是在应用部署环境的临时容器中运行的,直接在脚本里执行bundle exec rake my_rake_task就足够了——用heroku run会额外启动一个全新dyno,不仅多此一举,还可能导致任务和部署流程不同步。

调整后的release脚本(比如release-tasks.sh)可以这样写:

#!/bin/bash
set -e

# 先执行数据库迁移(如果你的迁移不是Heroku自动触发,建议加上这一步)
bundle exec rails db:migrate

# 执行自定义rake任务
bundle exec rake my_rake_task

然后在Procfile里配置release: ./release-tasks.sh,同时开启preboot,这个组合完全可行:preboot会让新旧版本dyno同时运行,直到新版本通过健康检查,再逐步切换流量,从根源上避免停机。

2. 迁移期间用户能否稳定访问旧版本数据库?

这核心取决于你的数据库迁移和rake任务是否向后兼容

  • 开启preboot后,Heroku的部署流程是:先执行release阶段任务(含迁移和rake任务),再启动新版本dyno,等新版本通过健康检查后,才会把流量切过去,旧版本dyno会继续运行约30分钟才被销毁。
  • 如果你的迁移是非破坏性的(比如新增字段、加索引,不删除旧版本依赖的字段/表,不修改字段类型),那旧版本应用依然能正常读写数据库——它不需要新结构,新结构也不会干扰它的运行。
  • 但如果你的迁移是破坏性的(比如删除旧字段、修改字段类型为旧版本不兼容的格式),那迁移完成后,旧版本应用可能直接报错,因为它依赖的数据库结构已经改变。
  • 至于你的rake任务(清空表再写入新数据),要确保新数据格式是旧版本应用能识别的,否则旧版本读取新数据时会出问题。

总结:只要保证迁移和数据更新是向后兼容的,用户就能在过渡期间稳定访问旧版本应用。如果有破坏性操作,建议分两步部署:先部署兼容新结构/数据的旧版本代码,再执行迁移和数据更新,最后部署新版本。

3. 能否通过Heroku环境变量按需触发发布脚本?

当然可以!你可以在release脚本里加一个环境变量的条件判断,只有当变量满足特定值时,才执行自定义rake任务。

比如修改后的release-tasks.sh

#!/bin/bash
set -e

# 先执行数据库迁移
bundle exec rails db:migrate

# 检查环境变量,按需触发rake任务
if [ "$RUN_CUSTOM_RAKE_TASK" = "true" ]; then
  echo "Starting custom rake task..."
  bundle exec rake my_rake_task
  echo "Custom rake task completed!"
fi

然后你可以通过Heroku CLI控制这个开关:

  • 需要执行rake任务时,设置变量:heroku config:set RUN_CUSTOM_RAKE_TASK=true --app myApp
  • 不需要时,要么设置为falseheroku config:set RUN_CUSTOM_RAKE_TASK=false --app myApp,要么直接删除变量:heroku config:unset RUN_CUSTOM_RAKE_TASK --app myApp

注意:每次部署都会执行release脚本,所以如果变量一直设为true,每次部署都会跑rake任务。如果只是特定部署需要执行,可以在部署前临时设置,部署完成后再改回来。


额外注意事项

  • 确保你的应用配置了健康检查:preboot依赖健康检查判断新版本是否就绪,如果健康检查没配置好,新版本可能永远不会被切流量,旧版本会一直运行。
  • 让你的rake任务保持幂等性:万一release任务失败重试,重复执行也不会导致数据混乱。
  • 注意release阶段的超时时间:Heroku默认release任务超时是15分钟,如果你的rake任务耗时超过这个时间,会导致部署失败,需要提前评估任务时长。
  • 分阶段处理破坏性迁移:如果必须做不兼容的数据库变更,一定要遵循“先兼容代码,再迁移,再清理旧代码”的流程,绝对避免直接停机操作。

内容的提问来源于stack exchange,提问作者Kruupös

火山引擎 最新活动