0

I want to automatically detect if I need to run heroku run rake db:migration after I have deployed a new release. If I find no migration is needed, then there is no need to put the live site into maintenance mode.

One approach would be a ruby script file that would run system("run rake db:version") to find current version, then examine the timestamp part of the files in db/migrate to find the latest version and do a db:migrate if the current version is older than the most recent timestamp in the db/migrate directory.

However this feels brittle, is there a more robust way?

Obromios
  • 15,408
  • 15
  • 72
  • 127

3 Answers3

1

Based on this Q&A, it looks like you should be able to do something like:

rails db:migrate:status
jvillian
  • 19,953
  • 5
  • 31
  • 44
1

Even better, why not run rake db:migrate as part of you deploy pipeline? If there are no migrations to apply this won't hurt anything, and if there are they'll automatically be applied. As a bonus, if the migration fails the whole deploy will fail.

To do this, add a release phase task to your Procfile, e.g.

release: rake db:migrate
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}

Commit and deploy as usual. You should see rake db:migrate being run automatically in the deploy output.

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
  • Normally if I am going to migrate, I put the site into maintenance mode to stop transactions happening whilst a migration is in progress. Does your answer, address this concern, i.e with your approach what happens if there are incoming transactions? Also, why is RACK_ENV development, when this is running in production? – Obromios Oct 25 '19 at 05:38
  • @Obromios, this isn't any worse than what you're already doing from a put-the-site-in-maintenance-mode perspective, and it's arguably better since it's automatic. Your current approach is to update your code and then see if you should migrate, only migrating after you figure that out. In the meantime, if any migrations need to be applied, your code and database are out of sync which will cause parts of your application to fail. – ChrisGPT was on strike Nov 11 '19 at 03:21
  • I agree that using ```rails db:migrate:status``` after the new release has been pushed can cause problems until the migration is completed. I like the release phase approach and will probably start using it, but it appears it can still leave the database in a partially migrated state. Please see my answer below for my current approach. I consider my answer tentative, so welcome feedback on it. – Obromios Nov 12 '19 at 09:56
  • @Obromios, your answer looks reasonable, but my experience is more on the Heroku side than the Rails side. Good luck! – ChrisGPT was on strike Nov 12 '19 at 21:24
0

My current approach is for a script to check whether the remote database is in sync with the release that is just about to be pushed using the versions_check method below. If the remote version is in sync, then push the new release without putting it in maintenance mode. If it is not in sync, then start maintenance mode, back up the database, push the new release, do the migrations and then take out of maintenance mode. Also post a temporary warning to all users that maintenance is starting.

require 'ostruct'   
def versions_check(remote: 'production')
      last_migration = Dir['db/migrate/*'].sort.last
      version = last_migration.gsub('db/migrate/','').split('_').first
      remote_migration = `heroku run rake db:version -r #{remote}`
      remote_version = remote_migration.split(' ').last
      OpenStruct.new(ok?: (version == remote_version), version: version, remote_version: version)
end
Obromios
  • 15,408
  • 15
  • 72
  • 127